[英]Casting to a base class using generics
我似乎在理解C#中的泛型时遇到了一些麻烦。
基本上,我有一个名为ConfigWorker
的基类和许多子类,它们都应使用从BaseConfig
派生的自己的配置类。
我要使用的ConfigWorker类应该在运行时动态确定,并以类的名称为参数。
我可以实例化给定其名称的子类,但是无论我尝试什么,我都无法将转换强制转换为明智的基类。
这是我的代码:
namespace DocumentHandler
{
public class BaseConfig
{
}
public class ConfigWorker<T> where T : BaseConfig
{
public virtual void Work(T options)
{
}
}
public class Worker1 : ConfigWorker<Worker1.Config>
{
public class Config : BaseConfig
{
public string test = "";
}
public override void Work(Config options)
{
//do something
}
}
public class Worker2 : ConfigWorker<Worker2.Config>
{
public class Config : BaseConfig
{
public string test = "";
}
public override void Work(Config options)
{
//do something else
}
}
public class Test
{
public static BaseConfig config;
public static void test()
{
(Activator
.CreateInstance(Type.GetType("DocumentHandler.Worker2"))
as ConfigWorker<BaseConfig>)
.Work(config);
}
}
}
关键是
(Activator
.CreateInstance(Type.GetType("DocumentHandler.Worker2"))
as ConfigWorker<BaseConfig>)
.Work(config);
强制转换为ConfigWorker<BaseConfig>
返回null,因为无法执行强制转换。
由于缺少类型参数,因此无法简单地ConfigWorker
为ConfigWorker
。
我还能尝试什么吗? CreateInstance
显然只是返回一个对象,我需要CreateInstance
该对象才能调用Work
方法
任何帮助表示赞赏。
Worker2的实例不是ConfigWorker ConfigWorker<BaseConfig>
! 这是ConfigWorker<Worker2.Config>
。 这是两种完全不同的类型。 泛型类是不变的。 只有接口和委托可以是协变或反变的。
在您的示例中, ConfigWorker
在T
甚至是反变的,这意味着您将T
用作方法的输入参数的类型。 因此,您尝试的实际上是危险的。
想象一下您的行将工作:您将获得类型为ConfigWorker<BaseConfig>
的变量,因此您可以依赖于此实例,该实例具有一个方法Work()
,该方法将BaseConfig
(或BaseConfig
派生的东西)作为参数。 所以没有什么可以阻止您像这样称呼它
worker.Work(new Worker1.Config());
编译正常。 但请稍等! 您的Worker2
不是说worker
是worker
Worker2
吗? Worker2
实例只能处理Worker2.Config
参数!
这样您就完全失去了类型安全性(好吧,如果允许的话,您会这样做)。
您的班级设计中存在缺陷。
工厂模式具有很好的解决方案,这似乎是一个好问题。 这是一个简化的解决方案
namespace DocumentHandler
{
public interface IBaseConfig
{
}
public class ConfiManager : IBaseConfig
{
}
public abstract class WorkerFactory
{
private readonly IBaseConfig _config;
protected WorkerFactory(IBaseConfig config)
{
this._config = config;
}
public virtual void Work()
{
}
}
public class Worker1 : WorkerFactory
{
private readonly IBaseConfig _config;
public Worker1(IBaseConfig config):base(config)
{
_config = config;
}
public string test = "";
public override void Work()
{
//do something
}
}
public class Worker2 : WorkerFactory
{
private readonly IBaseConfig _config;
public string test = "";
public Worker2(IBaseConfig config):base(config)
{
this._config = config;
}
public override void Work()
{
Console.WriteLine("Hello world");
}
}
public class Test
{
public static IBaseConfig config = new ConfiManager();
public static void test()
{
WorkerFactory worker =
(Worker2) Activator.CreateInstance(Type.GetType("DocumentHandler.Worker2"), config);
worker.Work();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.