[英]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.