这让我头晕目眩,希望有人能够找到解决方案。 下面是简化的情况代码。这里的目标是,我想要一个单独的,可重用的库,并且可以选择为每个实现定制这些类。所以我去继承:
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中访问此对象?
答案 0 :(得分:3)
这里最好的方法(在我看来,无论如何)是为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
}
}
}
答案 1 :(得分:3)
最好使用接口将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>
{
…
}
答案 2 :(得分:0)
由于Core不是协变的,因此会失败。一般来说,类不能协变。只有接口和委托才能协变。
要达到预期的行为,您可以将Core类定义为带有out参数的接口,如下面的
public interface ICore<out T>where T:Handler
{
T Handler {get;}
string Text { get; }
}