尝试设置本机属性时,动态关键字抛出RunTimebinderException

时间:2013-08-23 14:29:05

标签: c# .net c#-4.0 dynamic .net-4.0

我使用动态关键字来处理外部程序集,并且只要访问它的方法和原始类型成员就可以正常工作。因此,例如我的类动态加载类看起来像followig:

public class Student
{
    public bool IsGood { get; set; }
    public StudentType St { get; set; }
    public University University { get; set; }
}

我可以通过执行以下操作从程序集动态加载对象:

var assembly = Assembly.LoadFrom("//path");

Type type = assembly.GetType("TestFrameWork.Student");
var student = Activator.CreateInstance(type); 

以下代码失败:

student.IsGood = true;
        student.St = TestFrameWork.StudentType.SomethingElse;

学生类型是来自动态加载程序集的枚举;

我可以获得学生对象。现在是有趣的部分。我可以称之为方法。我可以得到它的所有属性。我可以设置它的原始属性

所以我几乎可以做学生.IsGood = true;它将设置该属性。如果我有int,float等类型的其他原始属性,那也是如此。

BUT

当我尝试将其设置为动态加载程序集的本机属性时失败并出现RuntimeBinderException

例如,

如果我尝试做学生.University = new University()其中大学是一种本地类型的装配。它失败。

这是堆栈跟踪:

  

at System.RuntimeTypeHandle.CreateInstance(RuntimeType type,Boolean   publicOnly,Boolean noCheck,Boolean& canBeCached,   RuntimeMethodHandleInternal&安培; ctor,布尔& bNeedSecurityCheck)at   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean   skipCheckThis,Boolean fillCache,StackCrawlMark& stackMark)at   System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,   Boolean skipCheckThis,Boolean fillCache,StackCrawlMark& stackMark)
  在System.Activator.CreateInstance(Type type,Boolean nonPublic)at   System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr,Binder   binder,Object [] args,CultureInfo culture,Object []   activationAttributes,StackCrawlMark& stackMark)at   System.Activator.CreateInstance(Type type,BindingFlags bindingAttr,   Binder binder,Object [] args,CultureInfo culture,Object []   activationAttributes)at   System.Reflection.Assembly.CreateInstance(String typeName,Boolean   ignoreCase,BindingFlags bindingAttr,Binder binder,Object [] args,   CultureInfo culture,Object [] activationAttributes)at   System.Reflection.Assembly.CreateInstance(String typeName)at   TaskManagementFramework.PluginModule.CreateInstanceT in   C:\ Dropbox的\ CPTFramework_DynamicLoading \ TaskManagementFramework \插件   Loading \ PluginModule.cs:第19行   TaskManagementFramework.PluginLifecycleManager.GetPluginInstance(字符串   id,String parentXmlSectionDescription,Type expectedInterface,   Boolean useSingleInstance,IPlugin&插件)   C:\ Dropbox的\ CPTFramework_DynamicLoading \ TaskManagementFramework \插件   Loading \ PluginLifecycleManager.cs:第53行   TaskManagementFramework.PluginsXmlParser.ParsePlugins(的XElement   pluginsListElement,String parentXmlSectionDescription,   PluginLifecycleManager pluginLifecycleManager,List`1&插件)   C:\ Dropbox的\ CPTFramework_DynamicLoading \ TaskManagementFramework \ XML   Parsing \ PluginsXmlParser.cs:第39行

知道为什么吗?我通过互联网搜索没有具体解决这个问题..

2 个答案:

答案 0 :(得分:2)

总结一下:.NET framework 4.0绝对不支持直接分配动态加载程序集的本机类型。

这意味着我们必须做一些上面答案中建议的事情:

Type type = assembly.GetType("TestFrameWork.Student");
 type.GetProperty("University").SetValue(student, new University(), null);

如果您在运行时加载整个程序集,那么您可能也没有大学类型ar编译时间。在这种情况下,您的解决方案是

type2 =  assembly.GetType("TestFrameWork.University");
type.GetProperty("University").SetValue(student, Activator.CreateInstance(type2`enter code here`), null);

希望这有帮助。

但我认为这是.Net 4.0中的一个错误。我可能错了

答案 1 :(得分:1)

我相信做这种事的正确方法就是这样

class Program
{
    static void Main(string[] args)
    {
        object d = new Person();
        d.GetType().GetField("Parent").SetValue(d,new Person("Test"));
        Console.WriteLine(((Person)d).Parent.name);
        Console.Read();
    }
}

public class Person{
    public String name = "";
    public Person Parent;

    public Person()
    {
    }
    public Person(String s)
    {
        name = s;
    }
}

将大学投射到对象中并使用反射设置值。这是一个简单代码的示例,只需将Person替换为任何大学:

如果这不起作用,可能意味着您的本机代码中的大学无法解析为大学,因为它们被视为两种不同的类型。因此,创建一个对象正在使用的大学实例,并为其设置值。完成后,设置您创建的实例。

像这样(它的伪代码顺便说一下):

var assembly = Assembly.LoadFrom("//path");

Type type = assembly.GetType("TestFrameWork.University");
var Uni = Activator.CreateInstance(type); 
type = assembly.GetType("TestFrameWork.Student");
var student = Activator.CreateInstance(type); 
student.University = Uni;

编辑:枚举 枚举有点棘手 以下是我认为有用的内容:

 class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();

        Type t = p.Enuminator.GetType();
        dynamic e = Activator.CreateInstance(t);
        FieldInfo [] FieldArray = t.GetFields();

        p.GetType().GetField("Enuminator").SetValue(p, FieldArray[3].GetValue(e));

        Console.WriteLine(p.Enuminator);
        Console.Read();
    }
}

public class Person{
    public String name = "";
    public Person Parent;
    public Enumtest Enuminator;

    public Person()
    {
    }
    public Person(String s)
    {
        name = s;
    }
}

public enum Enumtest
{
    chicken,
    monkey,
    frog
}

绝对是丑陋的;但是,只要您知道要提前导入的结构,就应该能够将其关闭。您还可以使用对象类型更改动态类型。我只是这样做,因为我试着做对了。