2

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

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

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

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

有什么想法吗?


编辑:

尝试后:

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

我收到许多错误:

  • 可访问性不一致:参数类型“MyAssembly.AbstractType”比方法“MyNameSpace.MyClass.AssignInitialValues(MyAssembly.AstractType)”更难访问
  • 'MyAssembly.AstractType' 由于其保护级别而无法访问
  • 找不到类型或命名空间名称“MyAssembly”(您是否缺少 using 指令或程序集引用?)
  • 找不到类型或命名空间名称“AbstractType”(您是否缺少 using 指令或程序集引用?)

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

关于问题出在哪里的任何线索?


更新:

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

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

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

它引用的行是这一行:

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

使用.Unwrap()get 解决了这个错误,我认为这是正确的方法(不确定)。但是,在运行程序时,当调用此代码时,我会得到一个 TypeLoadException。

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

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

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

“MyAssembly”是一个“命名空间”,但用作“变量”

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

  • 字符文字中的字符过多
  • 'System.Activator.CreateInstance(System.ActivationContext, string[])' 的最佳重载方法匹配有一些无效参数
  • 参数 1:无法从 'char' 转换为 'System.ActivationContext'
  • 参数 2:无法从 'string' 转换为 'string[]'

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

关于如何解决这个问题的任何想法?

4

3 回答 3

8

如果您有您的类型的完全限定名称,则根本不需要此foreach循环:

var myObject = (SomeBaseType) Activator.CreateInstance(null, myTypeName);
于 2012-09-15T00:16:52.647 回答
6

有很多方法可以满足您的需求。不是最好的表现:

Activator.CreateInstance(null, myTypeName);

你也可以使用这个:

var ci = Type.GetType(myTypeName).GetConstructor(Type.EmptyTypes);
var myTypeInstance = ci.Invoke(new object[]{})
于 2012-09-15T00:32:41.367 回答
4

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

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)的名称。

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

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

于 2012-09-16T05:56:47.270 回答