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

时间:2013-12-26 22:31:11

标签: c# generics inheritance

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

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

3 个答案:

答案 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)

最好使用接口将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>
{
    …
}

答案 2 :(得分:0)

由于Core不是协变的,因此会失败。一般来说,类不能协变。只有接口和委托才能协变。

要达到预期的行为,您可以将Core类定义为带有out参数的接口,如下面的

public interface ICore<out T>where T:Handler
{
    T Handler {get;}
    string Text { get; }
}