2013-04-17 8 views
9

コードを取り込んでメモリ内アセンブリを吐き出す便利なユーティリティメソッドがあります。このアセンブリは、反射して、他のように動作します(私はそれは問題べきではないと思うが、それは、CSharpCodeProviderを使用しています。)が、dynamicキーワードで使用した場合、RuntimeBinderExceptionで失敗しているようだ:動的に作成されたアセンブリで動的メソッドをバインドしようとすると、RuntimeBinderExceptionが発生します。

「オブジェクト」 「サウンド」の定義が含まれていません

例:

var assembly = createAssembly("class Dog { public string Sound() { return \"woof\"; } }"); 
var type = assembly.GetType("Dog"); 
Object dog = Activator.CreateInstance(type); 

var method = type.GetMethod("Sound"); 
var test1Result = method.Invoke(dog, null); //This returns "woof", as you'd expect 

dynamic dog2 = dog; 
String test2Result = dog2.Sound(); //This throws a RuntimeBinderException 

誰もがDLRがこれを処理することができない理由を知っていますか?このシナリオを修正するためにできることはありますか?

EDIT:

createAssembly方法:

免責事項:このようなもののいくつかはそれはしかし、自己説明的であるべき拡張メソッド、カスタムタイプなどが含まれています。

private Assembly createAssembly(String source, IEnumerable<String> assembliesToReference = null) 
{ 
    //Create compiler 
    var codeProvider = new CSharpCodeProvider(); 

    //Set compiler parameters 
    var compilerParameters = new CompilerParameters 
    { 
     GenerateInMemory = true, 
     GenerateExecutable = false, 
     CompilerOptions = "/optimize", 
    }; 

    //Get the name of the current assembly and everything it references 
    if (assembliesToReference == null) 
    { 
     var executingAssembly = Assembly.GetExecutingAssembly(); 
     assembliesToReference = executingAssembly 
      .AsEnumerable() 
      .Concat(
       executingAssembly 
        .GetReferencedAssemblies() 
        .Select(a => Assembly.Load(a)) 
      ) 
      .Select(a => a.Location); 
    }//End if 

    compilerParameters.ReferencedAssemblies.AddRange(assembliesToReference.ToArray()); 

    //Compile code 
    var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParameters, source); 

    //Throw errors 
    if (compilerResults.Errors.Count != 0) 
    {     
     throw new CompilationException(compilerResults.Errors);     
    } 

    return compilerResults.CompiledAssembly; 
} 

答えて

5

....(それはworkarroundない答えなので)コメントとしてこれを投稿しようとしたがbeacuse、それは長い間にだと行うことができませんでした。

var assembly = createAssembly("public class Dog { public string Sound() ... 
          ^

それは私のマシン上の問題を解決します。

+0

私の部分では愚かな間違いです。 'dynamic'はアクセシビリティを尊重しているので、別のアセンブリからの非公開コードを実行することはできません。一方、リフレクションはアクセシビリティについては気にしません。ありがとう。 – MgSam

0

これはワーキングアラウンドになる可能性があります。

//instead of this 
//dynamic dog2 = dog;  

//try this 
dynamic dog2 = DynWrapper(dog);  
String test2Result = dog2.Sound();//Now this works. 

public class DynWrapper : DynamicObject { 
     private readonly object _target; 


     public DynWrapper(object target) { 
      _target = target;     
     } 

     public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { 
      //for the sake of simplicity I'm not taking arguments into account, 
      //of course you should in a real app. 
      var mi = _target.GetType().GetMethod(binder.Name); 
      if (mi != null) { 
       result = mi.Invoke(_target, null);           
       return true; 
      } 
      return base.TryInvokeMember(binder, args, out result); 
     } 
    } 

PS:私はあなたのクラスpublicを作る