2013-04-17 7 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 

किसी को भी कारण है कि डीएलआर इस संभाल करने में सक्षम नहीं है पता है? क्या इस परिदृश्य को ठीक करने के लिए कुछ भी किया जा सकता है?

संपादित करें:

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

अपनी कक्षा public करें।

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

जो मेरी मशीन पर समस्या हल करता है।

+0

मेरे हिस्से पर मूर्खतापूर्ण गलती। 'गतिशील' अभिगम्यता का सम्मान करता है, इसलिए यह किसी अन्य असेंबली से गैर-सार्वजनिक कोड निष्पादित नहीं कर सकता है, जबकि प्रतिबिंब अभिगम्यता के बारे में थोड़ा सा परवाह नहीं करता है। धन्यवाद। – 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); 
     } 
    } 

पुनश्च: मैं एक टिप्पणी के रूप में इस पोस्ट करने के लिए (क्योंकि यह एक workarround नहीं एक जवाब है) की कोशिश लेकिन वह नहीं कर सके क्योंकि यह लंबे समय के लिए है ....

संबंधित मुद्दे