如何应用泛型约束来接受多级继承 C#

问题描述

我正在寻找一种方法支持泛型类型约束的多级继承。

通用通用接口

public interface ICommon<T>
{
    T OrignalData {get;set;}
    string ChangeJson {get;set;}
    T Merged {get;set;}
    void Inject();
}

公共基类实现 ICommon

public class Base <T>: ICommon<T>
{
    public T OrignalData {get;private set;}
    public string ChangeJson {get;set;}
    public T Merged {get;private set;}
    public void Inject(T orignal)
    {
        if (orignal == null)
            return;
       
        var settings = new JsonSerializerSettings
        {
            ObjectCreationHandling = ObjectCreationHandling.Auto
        };
        dynamic merged = orignal.Clone();
        JsonConvert.PopulateObject(this.ChangeJson,merged,settings);
        this.Merged  = merged;
        this.Orignal = orignal;
    }
}

部门类继承基类

public class Deparment : Base<Deparment>
{
}

OrgnizationDepartment 类继承了 Deparment

public class OrgnizationDepartment : Deparment
{

}

class View 期望 ICommon 必须在传递的调用上实现

public class View<T> where T : ICommon<T>
{
   //This class is totally dynamic to visualize any json data along with  old and new value of requested json for any class like department or org..
}

测试

public class Test
{
    public void TestConstraint()
    {
        //No error 
        var deptView = new View<Deparment>();

        //Error as Base not directly implemented on OrgnizationDepartment 
        var orgView = new View<OrgnizationDepartment>();
    }
}

我如何定义也应该支持多级的约束。

解决方法

一种方法是“组合优于继承”。

这是一个天真的例子,它仍然与您的代码相对接近:

using System;
using Newtonsoft.Json;
                    
public class Program
{
    public static void Main()
    {
        //No error 
        var deptView = new View<Deparment>();

        //Formerly Error 
        var orgView = new View<OrgnizationDepartment>();
    }
}

public interface ICommon<T> where T : ICloneable
{
    // returns a tuple
    (T,T,string) Inject(T original,string change);
}

public class Base <T>: ICommon<T> where T : ICloneable
{
   // we can reuse this...
   private readonly JsonSerializerSettings  settings = new JsonSerializerSettings
        {
            ObjectCreationHandling = ObjectCreationHandling.Auto
        };

    public (T,string change)
    {
        if (original is null)
            return default;
        
        // this forces T to implement ICloneable ... just saying...
        dynamic merged = original.Clone();
        
        JsonConvert.PopulateObject(change,merged,settings);
        return (original,change);
    }
}

public class Deparment : ICloneable,ICommon<Deparment>
{
    // could also be created in ctor. Maybe use Ctor injection.
    private readonly Base<Deparment> common = new Base<Deparment>();
    public object Clone(){return this;} // this is of course nonsense. Clone properly! I did this to avoid dotnetfiddle screaming at me.
    public (Deparment,Deparment,string) Inject(Deparment original,string change){
        return common.Inject(original,change);
    }
}

public class OrgnizationDepartment : ICloneable,ICommon<OrgnizationDepartment>
{
    private readonly Base<OrgnizationDepartment> common = new Base<OrgnizationDepartment>();
    public object Clone() {return this;}
    public (OrgnizationDepartment,OrgnizationDepartment,string) Inject(OrgnizationDepartment original,change);
    }
}