从字符串名称在程序集中创建类实例 [英] Create class instance in assembly from string name

查看:29
本文介绍了从字符串名称在程序集中创建类实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定这是否可行,而且我对在 C#.NET 中使用程序集还是很陌生.

I'm not sure if this is possible, and I'm quite new to using assemblies in C#.NET.

我想做的是在提供该类的字符串名称时创建该类的实例.像这样:

What I would like to do is to create an instance of a class when supplied the string name of that class. Something like this:

using MyAssembly;

namespace MyNameSpace
{
     Class MyClass
     {
          int MyValue1;
          int MyValue2;

          public MyClass(string myTypeName)
          {
               foreach(Type type in MyAssembly)
               {
                    if((string)type == myTypeName)
                    {
                         //create a new instance of the type
                    }
               }
               AssignInitialValues(//the type created above)
          }

          //Here I use an abstract type which the type above inherits from
          private void AssignInitialValues(AbstractType myClass)
          {
               this.value1 = myClass.value1;
               this.value2 = myClass.value2;
          }
      }
 }

显然,您无法将字符串与类型进行比较,但它说明了我正在尝试做的事情:从提供的字符串创建在不同程序集中找到的类型.

Obviously you cannot compare strings to types but it illustrates what I'm trying to do: create a type found in a different assembly from a supplied string.

有什么想法吗?

尝试后:

var myObject = (AbstractType) Activator.CreateInstance(null, myTypeName);
AssignInitialValues(myObject);

我收到了一些错误:

  • 不一致的可访问性:参数类型MyAssembly.AbstractType"比方法MyNameSpace.MyClass.AssignInitialValues(MyAssembly.AstractType)"更不易访问
  • 'MyAssembly.AstractType' 由于其保护级别而无法访问
  • 找不到类型或命名空间名称MyAssembly"(您是否缺少 using 指令或程序集引用?)
  • 找不到类型或命名空间名称AbstractType"(您是否缺少 using 指令或程序集引用?)
  • Inconsistent accessibility: parameter type 'MyAssembly.AbstractType' is less accessible than method 'MyNameSpace.MyClass.AssignInitialValues(MyAssembly.AstractType)'
  • 'MyAssembly.AstractType' is inaccessible due to it's protection level
  • The type or namespace name 'MyAssembly' could not be found (are you missing a using directive or an assembly reference?)
  • The type or namespace name 'AbstractType' could not be found (are you missing a using directive or an assembly reference?)

不确定为什么找不到程序集;我添加了对程序集的引用,并为程序集中的命名空间使用了 Using 指令.至于保护级别,它是调用只能是公共的类(或者更确切地说是类的构造函数).

Not exactly sure why it can't find the assembly; I've added a reference to the assembly and I use a Using Directive for the namespace in the assembly. As for the protection level, it's calling classes (or rather the constructors of classes) which can only be public.

有什么关于问题出在哪里的线索吗?

Any clues on where the problem is?

更新:

在浏览了几篇关于 SO 的文章后,我发现了这个:https://stackoverflow.com/a/1632609/360627一>公开 AbstractType 类解决了可访问性不一致的问题.

After looking through several articles on SO I came across this: https://stackoverflow.com/a/1632609/360627 Making the AbstractTypeclass public solved the issue of inconsistent accessibility.

新的编译器错误是这样的:

The new compiler error is this:

无法将类型System.Runtime.Remoting.ObjectHandle"转换为MyAssembly.AbstractType"

Cannot convert type 'System.Runtime.Remoting.ObjectHandle' to 'MyAssembly.AbstractType'

它引用的那一行是这样的:

The line it references is this one:

var myObject = (AbstractType) Activator.CreateInstance(null, myTypeName);

使用 .Unwrap() 让我克服了这个错误,我认为这是正确的方法(不确定).但是,当运行该程序时,我会在调用此代码时收到 TypeLoadException.

Using .Unwrap() get's me past this error and I think it's the right way to do it (uncertain). However, when running the program I then get a TypeLoadException when this code is called.

TypeLoadException: 无法从程序集MyNameSpace"加载类型AbstractType"...

TypeLoadException: Could not load type ‘AbstractType’ from assembly ‘MyNameSpace'...

我马上就能发现它寻找的类型是正确的,但它寻找的程序集是错误的.查看 Activator.CreateInstance(String, String) 方法发现 null 作为第一个参数意味着该方法将在执行程序集中查找.这与原始帖子中所需的行为相反.

Right away I can spot that the type its looking for is correct but the assembly it's looking in is wrong. Looking up the Activator.CreateInstance(String, String) method revealed that the null as the first argument means that the method will look in the executing assembly. This is contrary to the required behavior as in the original post.

我尝试使用 MyAssembly 作为第一个参数,但这会产生错误:

I've tried using MyAssembly as the first argument but this produces the error:

'MyAssembly' 是一个命名空间",但用作变量"

'MyAssembly' is a 'namespace' but is used like a 'variable'

认为这是由于 MyAssembly 不是字符串造成的.但是,如果我尝试 'MyAssembly',我会收到以下编译器错误:

I think that this is caused by MyAssembly not being a string. However if I try 'MyAssembly' I get the following compiler errors:

  • 字符文字中的字符过多
  • System.Activator.CreateInstance(System.ActivationContext, string[])"的最佳重载方法匹配有一些无效参数
  • 参数 1:无法从char"转换为System.ActivationContext"
  • 参数 2:无法从 'string' 转换为 'string[]'
  • Too many characters in character literal
  • The best overloaded method match for 'System.Activator.CreateInstance(System.ActivationContext, string[])' has some invalid arguments
  • Argument 1: cannot convert from 'char' to 'System.ActivationContext'
  • Argument 2: cannot convert from 'string' to 'string[]'

在我看来,它试图使用错误的重载.

Seems to me like it's trying to use the wrong overload.

对如何解决这个问题有任何想法吗?

Any thoughts on how to fix this?

推荐答案

好的,这就是答案.我已经使用真实代码对其进行了测试,并且可以正常工作.我不确定这是最好的方法还是最有效的方法.我对另外两个答案投了赞成票,因为它们帮助我走上了正轨,但这里是完整的答案.

Okay so this is the answer. I've tested it using real code and it works. I'm not sure if it's the best way or the most efficient way. I've upvoted the other two answers because they helped me get onto the right track but here is the full answer.

using MyAssembly;

namespace MyNameSpace
{
     Class MyClass
     {
          int MyValue1;
          int MyValue2;

          public MyClass(string myTypeName)
          {
               string assemblyName = Assembly.GetAssembly(typeof(AbstractType)).ToString();
               AbstractType selectedClass = (AbstractType)Activator.CreateInstance(assemblyName, myTypeName).Unwrap();
               AssignInitialValues(selectedClass);
          }

          private void AssignInitialValues(AbstractType myClass)
          {
               this.value1 = myClass.value1;
               this.value2 = myClass.value2;
          }
      }
 }

我用了三天的谷歌搜索,通过 SO 和 MSDN 进行搜索,但它就在那里.请注意,当使用 Activator.CreateInstance(String, String) 实例化类时,程序集名称(第一个参数)必须是完整的程序集名称,而不仅仅是 .dll(或 .exe)的名称.

Took me three days of googling, searching through SO and MSDN but there it is. Note that when instantiating a class with Activator.CreateInstance(String, String) the assembly name (first parameter) must be the full assembly name not just the name of the .dll (or .exe).

可以使用 string assemblyName = Assembly.GetAssembly(typeof(AbstractType)).ToString(); 检索程序集名称,其中 AbstractType 可以替换为类型您知道要在程序集中包含和定义.

The assembly name can be retrieved by using string assemblyName = Assembly.GetAssembly(typeof(AbstractType)).ToString(); where AbstractType can be replaced by a type you know to be contained and defined in the assembly.

类型名称(第二个参数)必须是完全限定名称,而不仅仅是类名称.

The type name (second parameter) must be the fully qualified name, not just the class name.

这篇关于从字符串名称在程序集中创建类实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆