如何访问从泛型类继承的对象



这让我头疼,我希望有人能有智慧找到解决方案。下面是情况的简化代码。这里的目标是,我想要一个单独的、可重用的库,并可以选择为每个实现自定义这些类。所以我去继承:

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 中访问此对象?

最好使用接口将CoreHandler相互绑定。您仍然可以保持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; }
}

最新更新