2011-07-26 10 views
4

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); 
    } 
} 

ありがとうございました。

+5

あなたは本当に醜いものを作ろうとしています。これが本当に必要なのですか? –

+0

私が掲載したコードスニペットは、私の質問を説明するのに役立つ概念を示すためのものです。私はそれが醜い何かを作成するために使用することができることを理解する - ありがとう。 – RepDbg

答えて

8

refキーワードを使用しなくても、パラメータのオブジェクト参照を置き換えることを考えています。

これは単純に起こりません。あなたのメソッド(ref)が呼び出されると、CLRはメソッドが受け取る渡された参照のコピーを作成します。あなたのメソッドは、その心臓の内容へのその参照を変更することができますは、文書化されていないキーワードを使って何をトリッキーにしても、コピーが作成された参照(呼び出し元のメソッドによって渡された参照)賢いCIL。

なぜ、コレクションの初期化子に渡されたパラメータを置き換えようとしているのかが私の目の前にあります。それはしてはいけないことをするコードの匂いがする。

+0

返信ありがとう - 私はこれが管理されたC + +で達成されると思った(私は間違っている?)。それでは、どうすればCLRの限界になりますか?インターフェイスを使用している場合、実装を切り替えるのがなぜ問題になるのでしょうか? – RepDbg

+2

私は関数が非参照パラメータを変更できるようにする言語を知らない。これは、.NETでは(CLRではサポートされていないため)実行できません。つまり、Managed C++やC++/CLIでは実行できません。 –

関連する問題