【问题标题】:Dynamic keyword throwing RunTimebinderException when trying to set native property尝试设置本机属性时抛出 RunTimebinderException 的动态关键字
【发布时间】:2013-08-26 15:41:23
【问题描述】:

我正在使用动态关键字来处理外部程序集,就访问它的方法和原始类型成员而言,它工作正常。所以例如我的类动态加载的类看起来像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;

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

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

所以我几乎可以做 student.IsGood = true;它将设置该属性。如果我有其他类型为 int、float 等的原始属性,这同样适用。

但是

当我尝试将其设置为动态加载程序集的原生属性时,它会因 RuntimeBinderException 而失败

例如,

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

这是堆栈跟踪:

在 System.RuntimeTypeHandle.CreateInstance(RuntimeType 类型,布尔值 publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) 在 System.RuntimeType.CreateInstanceSlow(布尔 publicOnly,布尔 skipCheckThis、布尔填充缓存、StackCrawlMark 和 stackMark)在 System.RuntimeType.CreateInstanceDefaultCtor(布尔 publicOnly, Boolean skipCheckThis、Boolean fillCache、StackCrawlMark& stackMark)
在 System.Activator.CreateInstance(类型类型,布尔非公共)在 System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr,Binder 活页夹,对象 [] 参数,CultureInfo 文化,对象 [] 激活属性、StackCrawlMark 和 stackMark)在 System.Activator.CreateInstance(类型类型,BindingFlags bindingAttr, Binder 活页夹、Object[] 参数、CultureInfo 文化、Object[] 激活属性)在 System.Reflection.Assembly.CreateInstance(字符串类型名称,布尔值 ignoreCase,BindingFlags bindingAttr,Binder binder,Object[] args, CultureInfo 文化,对象 [] 激活属性)在 System.Reflection.Assembly.CreateInstance(String typeName) 在 TaskManagementFramework.PluginModule.CreateInstanceT 在 c:\Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\Plugin 加载\PluginModule.cs:第 19 行 TaskManagementFramework.PluginLifecycleManager.GetPluginInstance(字符串 id,字符串 parentXmlSectionDescription,类型预期接口, Boolean useSingleInstance, IPlugin& plugin) in c:\Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\Plugin Loading\PluginLifecycleManager.cs:第 53 行 TaskManagementFramework.PluginsXmlParser.ParsePlugins(XElement pluginsListElement, String parentXmlSectionDescription, PluginLifecycleManager pluginLifecycleManager, List`1& plugins) in c:\Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\XML 解析\PluginsXmlParser.cs:第 39 行

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

【问题讨论】:

  • 提供堆栈跟踪。
  • 我在问题中添加了堆栈跟踪
  • 学生中的大学类型似乎与您尝试分配的类型不同。我希望有一个无效的强制转换异常,但该信息可能被隐藏或作为内部异常提供。
  • 您可能还想提供一个小的独立复制问题供其他人调试。
  • @leppie :我的代码很小。我刚刚编辑了问题并添加了失败的代码。如果您需要更多信息,请告诉我..

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


【解决方案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
}

这绝对是丑陋的;但是,只要您提前知道要尝试导入的结构,您就应该能够做到这一点。您也可以使用对象类型更改动态类型。我这样做只是因为我想把它做对。

【讨论】:

  • 所以试着按照你的建议去做。 type.GetField("Fieldname") 不断返回 null
  • 我不应该使用 GetProperty 而不是 GetField 吗?
  • 你试过第二个选项了吗?
  • 您的方法 1 自行工作。我所要做的就是用 GetProperty 替换 GetField :type.GetProperty("University").SetValue(student, Activator.CreateInstance(type4), null);
  • 如您所见,我用 setvalue 中的动态替换了具体对象,它似乎仍然有效。但是当我用枚举尝试同样的事情时,它失败了。但我会为此提出一个新问题。谢谢。
【解决方案2】:

总结一下:.NET 框架 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 中的一个错误。我可能错了

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 1970-01-01
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多