这让我头疼,我希望有人能有智慧找到解决方案。下面是情况的简化代码。这里的目标是,我想要一个单独的、可重用的库,并可以选择为每个实现自定义这些类。所以我去继承:
namespace Library {
//a class that holds stuff together
public class Core<THandler> where THandler:Handler
{
public THandler handler;
public string text = "Something";
}
//class that react for extern events, say a keyboard events
public class Handler
{
protected object core;
public Handler(object _core) {
core = _core;
}
protected virtual void OnEvent() {
//how to access 'core.text' ??
var a = (Core<Handler>)core; //raises System.InvalidCastException
// since 'core' actualy contains
// an instance of MyCore
}
}
}
namespace MyImplementation {
public class MyCore : Library.Core<MyHandler>
{
}
public class MyHandler : Library.Handler
{
protected override void OnEvent() {
base.OnEvent();
//and what's the preferable option for accessing 'core' here?
var a = (MyCore)core; //I use this
}
}
}
由于 Handler.core 包含 MyCore 的实例,如何在 Hanlder.OnEventmethod 中访问此对象?
最好使用接口将Core
和Handler
相互绑定。您仍然可以保持Core<T>
通用。泛型类型约束不允许你声明循环依赖关系,否则这是使核心工作所必需的。
请注意,有问题的强制转换无效的根本原因不是core
实例是从您的示例中MyCore
的,而是因为MyCore
继承自Core<MyHandler>
而不是Core<Handler>
。
如果出于某种原因,您坚持保留当前设计,您也可以Handler
泛型,将其祖先作为类型参数传递,并像这样修复强制转换:
public class Handler<THandler> where THandler : Handler<THandler>
{
protected object core;
public Handler(object _core) {
core = _core;
}
public virtual void OnEvent() {
// this works
var a = (Core<THandler>)core;
}
}
因此,为了使它更加类型安全并避免强制转换,构造函数应如下所示:
protected Core<THandler> core;
public Handler(Core<THandler> _core) {
core = _core;
}
然后,MyHandler
声明将很自然地看起来像这样:
public class MyHandler : Handler<MyHandler>
{
…
}
最好的方法(无论如何,在我看来)是为您需要在Core
中访问的方法和属性创建一个接口。
例如,类似于以下内容的内容:
namespace Library {
public interface ICore {
string text {get; set;}
}
//a class that holds stuff together
public class Core<THandler> : ICore where THandler : Handler
{
public THandler handler;
private string m_Text = "Something";
public string text
{
get
{
return m_Text;
}
set
{
m_Text = value;
}
}
}
//class that react for extern events, say a keyboard events
public class Handler
{
protected ICore core;
public Handler(object _core) {
core = (ICore)_core;
}
protected virtual void OnEvent() {
Debug.WriteLine(core.text);
}
}
}
namespace MyImplementation {
public class MyCore : Library.Core<MyHandler>
{
}
public class MyHandler : Library.Handler
{
protected override void OnEvent() {
base.OnEvent();
//and what's the preferable option for accessing 'core' here?
var a = (MyCore)core; //I use this
}
}
}
强制转换失败,因为核心不是协变的。类通常不能是协变的。只有接口和委托可以是协变的。
要达到预期的行为,您可以将 Core 类定义为带有 out 参数的接口,如下所示
public interface ICore<out T>where T:Handler
{
T Handler {get;}
string Text { get; }
}