ref 키워드를 사용하지 않고도 매개 변수의 객체 참조를 교체 할 수 있기를 원합니다.ref 키워드 (IL 사용)를 사용하지 않고 매개 변수의 참조 교체
ref를 사용하는 것을 피하는 이유는 Add(T item)
메서드를 찾는 컬렉션 초기화 프로그램 호출을 보존하는 것이고 컬렉션 클래스가 참조를 다른 인터페이스 구현으로 바꿔야 할 필요가 있기 때문입니다.
나는 이것을하기 위해 몇 가지 다른 방법을 시도했다. 먼저 문서화되지 않은 키워드 __makeref
, __refvalue
및 __reftype
을 사용해 보았습니다.
두 번째로 ref 매개 변수를 사용하여 디스 어셈블 된 유사한 호출을 보면서 관측 한 일부 IL과 함께 DynamicMethod
을 만들려고했습니다.
using System;
using System.Collections.Generic;
using System.Collections;
using System.Reflection.Emit;
using System.Reflection;
interface IRecord
{
string Name { get;}
}
class ImpA : IRecord
{
public string Name { get { return "Implementation A"; } }
}
class ImpB : IRecord
{
public string Name { get { return "Implementation B"; } }
}
class RecordList<T> : IEnumerable<T>
{
//// Standard Add method (of course does not work)
//public void Add(T item)
//{
// item = (T)(object)new ImpB();
//}
// ref method (works great but the signature cannot be
// used by the collection initializer)
public void Add(ref T item)
{
IRecord newItem = new ImpB();
item = (T)newItem;
}
//// Using System.TypedReference (does not work)
//public void Add(T item)
//{
// T newItem = (T)(object)new ImpB();
// TypedReference typedRef = __makeref(item);
// __refvalue(typedRef, T) = newItem;
//}
// Using Reflection.Emit DynamicMethod (This method should work but I need help)
public void Add(T item)
{
IRecord newItem = new ImpB();
System.Reflection.MethodAttributes methodAttributes =
System.Reflection.MethodAttributes.Public
| System.Reflection.MethodAttributes.Static;
DynamicMethod dm = new DynamicMethod("AssignRef",
methodAttributes,
CallingConventions.Standard,
null,
new Type[] { typeof(IRecord), typeof(IRecord) },
this.GetType(),
true);
ILGenerator generator = dm.GetILGenerator();
// IL of method
//public static void Add(ref item, ref newItem)
//{
// item = newItem;
//}
// -- Loading Params (before call to Add() --
//L_002b: ldloca.s sb // this is the ref variable
//L_002d: ldloc.2 // The other variable
// -- Add method IL --
//L_0000: nop
//L_0001: ldarg.0
//L_0002: ldarg.1
//L_0003: stind.ref
//L_0004: ret
generator.Emit(OpCodes.Ldarga_S, 0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stind_Ref);
generator.Emit(OpCodes.Ret);
Action<IRecord, IRecord> AssignRef =
(Action<IRecord, IRecord>)dm.CreateDelegate(
typeof(Action<IRecord, IRecord>));
AssignRef((IRecord)item, (IRecord)newItem);
}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
IRecord imp = new ImpA();
Console.WriteLine("Original implementation: {0}\n", imp.Name);
// Calls Add Implicitly
RecordList<IRecord> records = new RecordList<IRecord> { imp };
// Prints "Implementation A"
Console.WriteLine("After Add Method: {0}", imp.Name);
records.Add(ref imp); // Explicit call with ref
// Prints "Implementation B"
Console.WriteLine("After Add Ref method: {0}\n", imp.Name);
}
}
감사합니다 : 여기
이 보여 몇 가지 코드입니다.
정말 추악한 것을 만들려고합니다. 너 정말 필요해/원하니? –
내가 게시 한 코드 스 니펫은 내 질문을 설명하는 데 도움이되는 개념을 보여주기위한 것입니다. 나는 그것이 추악한 무언가를 창조하는 데 사용될 수 있다는 것을 알고 있습니다 - 감사합니다. – RepDbg