4

我正在使用动态关键字与外部程序集一起工作,就访问它的方法和原始类型成员而言,它工作正常。因此,例如,我的类动态加载的类如下所示:

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

它在以下代码上失败:

学生.IsGood = true;
学生.St = TestFrameWork.StudentType.SomethingElse;

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

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

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

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

例如,

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

这是堆栈跟踪:

在 System.RuntimeTypeHandle.CreateInstance(RuntimeType 类型,Boolean publicOnly,Boolean noCheck,Boolean& canBeCached,RuntimeMethodHandleInternal& ctor,Boolean& bNeedSecurityCheck)在 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache,StackCrawlMark 和 stackMark)在 System.RuntimeType.CreateInstanceDefaultCtor (Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark & stackMark)
在 System.Activator.CreateInstance(Type type, Boolean nonPublic) 在 System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfoculture, Object[] activationAttributes, StackCrawlMark& stackMark) 在 System.Activator.CreateInstance(Type类型、BindingFlags bindingAttr、BindingFlags bindingAttr、Object[] args、CultureInfo 文化、Object[] activationAttributes) at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo 文化, System.Reflection.Assembly.CreateInstance(String typeName) 中的 Object[] activationAttributes),位于 c:\Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\Plugin Loading\PluginModule.cs 中的 TaskManagementFramework.PluginModule.CreateInstanceT:c:\Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\Plugin Loading\PluginLifecycleManager.cs 中 TaskManagementFramework.PluginLifecycleManager.GetPluginInstance(String id, String parentXmlSectionDescription, Type expectedInterface, Boolean useSingleInstance, IPlugin& plugin) 的第 19 行:TaskManagementFramework.PluginsXmlParser.ParsePlugins( XElement pluginsListElement, String parentXmlSectionDescription, PluginLifecycleManager pluginLifecycleManager, List`1& plugins) in c:\Dropbox\CPTFramework_DynamicLoading\TaskManagementFramework\XML Parsing\PluginsXmlParser.cs:line 39\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 Parsing\ PluginsXmlParser.cs:第 39 行\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 Parsing\ PluginsXmlParser.cs:第 39 行

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

4

2 回答 2

3

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

于 2013-08-23T19:20:47.147 回答
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
}

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

于 2013-08-23T15:15:15.720 回答