C# 创建一个只知道类名的对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/296251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:05:54  来源:igfitidea点击:

Create an object knowing only the class name?

c#.netreflectionconfiguration

提问by Anthony Mastrean

I have a set of classes, each one is a different strategyto do the same work.

我有一组类,每个类都是做相同工作的不同策略

namespace BigCorp.SuperApp
{
    public class BaseClass { }
    public class ClassA : BaseClass { }
    public class ClassB : BaseClass { }
}

The choice of which strategy to use is configurable. I want to configure only the class name 'ClassB' instead of the full type name 'BigCorp.SuperApp.ClassB' in the app.config file.

选择使用哪种策略是可配置的。我只想在 app.config 文件中配置类名“ClassB”而不是完整的类型名“BigCorp.SuperApp.ClassB”。

<appConfig>
   <SuperAppConfig>
      <Handler name="ClassB" />
   </SuperAppConfig>
</appConfig>

However, the reflection calls fail because they expect the full type name, particularly

但是,反射调用失败,因为它们需要完整的类型名称,尤其是

Type t = Type.GetType("ClassB"); // results in t == null
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

How can I get this to work while configuring only the class name? Concatenate the namespace to the class name for full type name? Is there another reflection call that works?

如何在仅配置类名时使其工作?将命名空间连接到类名以获得完整类型名称?还有另一个有效的反射调用吗?

If you think this is useless and I should expect the configuration to contain the full type name, I am open to that solution! Just provide rationale to convince me.

如果您认为这没有用,并且我应该期望配置包含完整的类型名称,那么我愿意接受该解决方案!只是提供理由来说服我。

(I will not be loading a type from outside this assembly/namespace)

(我不会从这个程序集/命名空间之外加载类型)

采纳答案by Bryan Watts

Since you know all classes will be coming from the same namespace, configure it once and use that:

因为你知道所有的类都来自同一个命名空间,所以配置一次并使用它:

<appConfig>
   <SuperAppConfig handlerNamespace="BigCorp.SuperApp">
      <Handler class="ClassB" />
   </SuperAppConfig>
</appConfig>

Edit:I changed nameto classto better denote the meaning of that attribute.

编辑:我将名称更改为class以更好地表示该属性的含义。

回答by Marc Gravell

Either use the assembly-qualified-name, or get hold of the Assembly and use Assembly.GetType(name). In this case, since you want the types in the config file, assembly-qualified is a valid way to go - but since you know all your types are in the same assembly:

要么使用程序集限定名称,要么获取程序集并使用Assembly.GetType(name). 在这种情况下,由于您想要配置文件中的类型,因此程序集限定是一种有效的方法 - 但因为您知道所有类型都在同一个程序集中:

Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly!
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);

The static Type.GetType(string)has probing rules that often cause confusion... it looks at the calling assembly, and a few system assemblies - but not all loaded assemblies.

静态Type.GetType(string)具有经常引起混淆的探测规则......它查看调用程序集和一些系统程序集 - 但不是所有加载的程序集。

回答by Kyle Trauberman

(I will not be loading a type from outside this assembly/namespace)

because of the above line, it is safe to assume that you know what the namespace is. Couldn't you do something like:

由于上面这行,可以安全地假设您知道命名空间是什么。你不能做这样的事情:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

If you expect to possibly be able to add additional strategy classes to be loaded in the future, perhaps via an additional assembly, you would need to fully qualify your class name. This is recommended anyway, since you would be able to provide enhanced extendability for your application.

如果您希望将来能够添加要加载的其他策略类,也许是通过附加程序集,您需要完全限定您的类名。无论如何建议这样做,因为您将能够为您的应用程序提供增强的可扩展性。

回答by Anthony Mastrean

I'm going with the full type name in the application configuration. Below is a slightly more complete, but still trivial example

我将在应用程序配置中使用完整的类型名称。下面是一个稍微更完整但仍然微不足道的例子

<SuperAppConfig>
   <ObjectConfig provider="BigCorp.SuperApp.ClassA">
      <add name="one" />
      <add name="two" />
   </ObjectConfig>
</SuperAppConfig>

And the factory class that actually creates this

而实际创建这个的工厂类

private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
    Type t = a.GetType(providerName)
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
    return o;
}

回答by citronas

BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

Might also result from the fact, that CreateInstance does not return an instance of BaseClass, rather than an instance of BaseClass wrapped into an ObjectHandle.

也可能是因为 CreateInstance 不返回 BaseClass 的实例,而不是将 BaseClass 的实例包装到 ObjectHandle 中。

Cast into your BaseClass after you used the UnWrap method.

使用 UnWrap 方法后转换到您的 BaseClass 中。