在 C# 中继承泛型

Posted

技术标签:

【中文标题】在 C# 中继承泛型【英文标题】:Inheriting a generic in c# 【发布时间】:2015-05-12 15:00:44 【问题描述】:

我继承了一个大型代码库,并且正在尝试在框架中实现一些新功能。基本上,为了以“正确”的方式进行操作,我必须修改框架的整个结构。因为我不是设计框架的人,也不是读心者,所以这样做可能不会发生(尽管我真的很想自己从头开始重新设计它)。

所以为了做我想做的事,我正在尝试实现一个装饰器模式。 This answer from maliger 表明我在下面所做的事情是完全有效的。但是,mono 似乎不喜欢它。当我声明 HappyDecorator 时,它抱怨 T 不能派生出来

请原谅这个过于简单的例子,但它明白了重点。

public class HappyObject

    public virtual void print()
    
        Console.WriteLine ("I'm happy");
    


public class VeryHappyObject : HappyObject

    public override void print()
    
        Console.WriteLine ("I'm very happy");
    

    public void LeapForJoy()
    
        Console.WriteLine("Leaping For Joy!");
    


public class SuperHappyObject : VeryHappyObject
    
    public override void print()
    
        Console.WriteLine ("I'm super happy!");
    

    public void DieOfLaughter()
    
        Console.WriteLine("Me Dead!");
    


public class HappyDecorator<T> : T where T : HappyObject

    public string SpecialFactor  get; set; 

    public void printMe()
    
        Console.WriteLine (SpecialFactor);
        print();
    

class MainClass

    public static void Main (string[] args)
    
        HappyDecorator<HappyObject> obj = new HappyDecorator<HappyObject> ();
        obj.SpecialFactor = Console.ReadLine();
        obj.printMe();
    

【问题讨论】:

您是否收到错误消息?或者它的行为与预期有何不同? 这不是遵循装饰器模式的方式。 obj obect 应该在他的构造函数中获得一个 HappyDecorator。 您不能继承泛型类型参数,这正是您的代码示例的错误消息所说的。哪一部分你不明白? 听起来你应该摆脱所有 cr_p 并改用System.Action&lt;T&gt;。创建类只是为了保存这样的函数被称为“名词王国中的执行”,这是一种疾病,主要影响设计糟糕的古老语言,如 java,而 C# 具有适当的特性来处理这个问题,而无需不得不创建无穷无尽的类层次结构。 你不能继承T。要么继承HappyObject,要么注入并包装T。我会选择后者。 【参考方案1】:

您正在向 T 键入 HappyDecorator,但在该类中没有可使用的 T 实例。

public class HappyDecorator<T> where T : HappyObject

    private readonly T _instance;

    public HappyDecorator(T instance)
    
        _instance = instance;
    

    public string SpecialFactor  get; set; 

    public void printMe()
    
        Console.WriteLine(SpecialFactor);
        _instance.print();
    

另一种选择是使用泛型方法而不是泛型类来构造它。不过,它并不是真正的装饰器:

public class HappyDecorator

    public string SpecialFactor  get; set; 

    public void printMe<T>(T instance) where T : HappyObject
    
        Console.WriteLine(SpecialFactor);
        instance.print();
    

然后像这样调用:

        HappyDecorator obj = new HappyDecorator();
        obj.SpecialFactor = Console.ReadLine();
        obj.printMe(new HappyObject()); 

【讨论】:

HappyDecorator 在 OPs 代码示例中继承 T,所以它是实例本身。 除非语法不正确且无法编译。那么它是否应该继承HappyObject,在这种情况下,泛型的好处就没有了。 我知道这不是一个有效的语法。在您提出解决方法之前,我希望您的回答能说明这一点:) 第二个绝对不是我想做的,对象必须以某种方式继承HappyObject,并且必须能够这样使用。第一个解决方案带来了一个问题,因为如果我将 VeryHappyObjectSuperHappyObject 传递给构造函数,我将无法访问这两个对象中包含的特殊字段。不幸的是,我的例子没有正确反映这一点。我将对其进行编辑以使其更清晰。 放弃HappyDecorator 类,将SpecialFactor 和printMe 移至基类,只创建您关心的正确实例怎么样?否则装饰器类将需要暴露 T 以便调用它的方法。【参考方案2】:

我认为这就是你想要做的:

    public interface IhappyObject
    
        void Print();
    

    public class HappyObject : IhappyObject
    
        private IhappyObject obj;

        public HappyObject(IhappyObject obj)
        
            this.obj = obj;
        

        public void Print()
        
            obj.Print();
        
    

    public class VeryHappyObject : IhappyObject
    
        public void Print()
        
            Console.WriteLine("I'm very happy");
        
    

    public class SuperHappyObject : IhappyObject
    
        public void Print()
        
            Console.WriteLine("I'm super happy!");
        
    

    static void Main(string[] args)
    
        HappyObject obj = new HappyObject(new SuperHappyObject());
        obj.Print();
    

【讨论】:

嗯,不完全是。我没有选择传统装饰器模式的原因是我想避免显式包装方法。当然,实际的代码(我拒绝称这种可恶是我自己的工作)比我提供的示例要复杂得多。 例如,假设VeryHappyObjectSuperHappyObject 的参数不包含在接口IHappyBbject 中。如果我正确理解了您的实现,具体来说,假设他们分别拥有LeapForJoy()DieOfLaughter() 方法(但不是两者都有)。然后我必须在界面中定义这两个函数,这并不是我想要做的,因为实际上这些对象比我想象的要复杂得多,这样做是真正的 PITA。

以上是关于在 C# 中继承泛型的主要内容,如果未能解决你的问题,请参考以下文章

私有成员是不是在 C# 中继承?

为啥我不能在 C# 中继承一个类? [复制]

C#中继承问题

C#中继承对象的内存分配

如何在c#中继承非继承属性

如何使用 Azure WCF 中继和混合连接按钮?