refキーワードを使用せずに、パラメータのオブジェクト参照を置き換えることを検討しています。refキーワード(ILを使用)を使用せずにパラメータのrefを置き換えます。
refを使用しない理由は、Add(T item)
メソッドを探すコレクションイニシャライザの呼び出しを保持することです。コレクションクラスでは、参照の代わりにそのインターフェイスの別の実装を使用する必要があります。
私はこれを行うにはいくつかの異なる方法を試しました。まず、文書化されていないキーワード__makeref
,__refvalue
、および__reftype
を使ってみました。
2番目に、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