代码之家  ›  专栏  ›  技术社区  ›  Lost

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

  •  4
  • Lost  · 技术社区  · 12 年前

    我使用dynamic关键字处理外部程序集,就访问它的方法和基元类型成员而言,它工作得很好。例如,我的类动态加载的类看起来如下:

    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=真;
    student.St=测试框架工作.StudentType.SomethingElse;

    Student Type是来自动态加载程序集的枚举;

    我可以拿到学生的物品。现在是有趣的部分。我可以称之为方法。我可以得到它的所有财产。我可以设置它的原始财产

    所以我几乎可以做学生。IsGood=true;并且它将设置该属性。如果我有int、float等类型的其他基本财产,也同样如此。

    但是

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

    因此,例如,

    如果我尝试做student.University=new University(),其中University是本地类型的加载程序集。它失败了。

    这是堆栈跟踪:

    在System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,布尔值 publicOnly,布尔noCheck,布尔&canBeCached中, 运行时方法句柄内部&ctor,布尔型&b需要安全检查) System.RuntimeType.CreateInstanceSlow(仅布尔型publicOnly,布尔型 skipCheckThis,布尔fillCache,StackCrawlMark&堆叠标记) System.RuntimeType.CreateInstanceDefaultCtor(仅布尔公共, 布尔skipCheckThis,布尔fillCache,StackCrawlMark&堆叠标记)
    位于System.Activator.CreateInstance(类型类型,布尔非公共) System.RuntimeType.CreateInstanceImpl(绑定标志bindingAttr,绑定器 绑定器,Object[]参数,CultureInfo区域性,Object[] activationAttributes,StackCrawlMark&堆叠标记) System.Activator.CreateInstance(类型类型,BindingFlags bindingAttr, 活页夹,Object[]参数,CultureInfo区域性,Object[] activationAttributes)在 System.Reflection.Assembly.CreateInstance(字符串类型名称,布尔值 ignoreCase,BindingFlags bindingAttr,绑定器绑定器,Object[]参数, CultureInfo区域性,Object[]activationAttributes)位于 位于的System.Reflection.Assembly.CreateInstance(字符串类型名称) 中的TaskManagementFramework.PluginModule.CreateInstanceT c: \Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\插件 正在加载\ PluginModule.cs:第19行 任务管理框架.PluginLifecycleManager.GetPluginInstance(字符串 id,字符串parentXmlSectionDescription,类型expectedInterface, 布尔值useSingleInstance,IPlugin&插件) c: \Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\插件 正在加载\PluginLifecycleManager.cs:line 53 任务管理框架.PluginsXmlParser.ParsePlugins(XElement pluginsListElement,字符串parentXmlSectionDescription, 插件生命周期管理器插件生命周期管理员,列表`1&插件) c: \Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\XML 解析\PluginsXmlParser.cs:行39

    知道为什么吗?我在网上搜索了一下,没有什么特别针对这个问题的。。

    2 回复  |  直到 12 年前
        1
  •  3
  •   Lost    12 年前

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

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

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

    如果您在运行时加载整个程序集(可能是这样),那么您也不会有University类型的ar编译时。在这种情况下,您的解决方案是

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

    希望这能有所帮助。

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

        2
  •  1
  •   Aelphaeis John    12 年前

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

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

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

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

    像这样(其伪码btw):

    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
    }
    

    这绝对是丑陋的;然而,只要您提前知道要导入的结构,就应该能够实现这一点。也可以使用“对象类型”更改“动态”类型。我这么做只是因为我努力把事情做好。

    推荐文章