如何使用抽象 class 创建通用列表?

How do I create a generic List using abstract class?

我有一个Jsonclass"GetAllDevices()"。我的 JSON 响应由 Array/List 个对象组成,其中每个对象都具有以下通用属性。

public class GetAllDevices
{
    [JsonProperty("_id")]
    public string Id { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("actions")]
    public Action[] Actions { get; set; }

    public class Action
    {
        public string _id { get; set; }
        public Action_Def action_def { get; set; }
    }

    public class Action_Def
    {
        public string _id { get; set; }
        public string name { get; set; }
    }
}

我想创建 2 个通用列表,其中包含基于其 "type" 的所有上述属性。 lstfoo1 列表包含类型="foo1" 的所有属性(_id、名称类型和操作)。同样,lstfoo2 是一个包含上述属性的列表,其中 type="foo2".

到目前为止我做了什么:

string strJson=getJSON();
Foo1 lstfoo1=new Foo1();
Foo2 lstfoo2=new Foo2();
List<Foo1> foo1list= lstfoo1.GetDeviceData(strJson);
List<Foo2> foo2list = lstfoo2.GetDeviceData(strJson);


public class AllFoo1: GetAllDevices
{
}

public class AllFoo2: GetAllDevices
{
}

public abstract class HomeDevices<T>
{
    public string type { get; set; }
    public string _id { get; set; }
    public List<AllFoo1> lstfoo1{ get; set; }
    public List<AllFoo2> lstfoo2{ get; set; }
    public abstract List<T> GetDeviceData(string jsonResult);
}

public class Foo1: HomeDevices<AllFoo1>
{
    public Foo1()
    {
        type = "foo1";
    }

    public override List<AllFoo1> GetDeviceData(string jsonResult)
    {
        var lst =Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo1>>(jsonResult);
        var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
        return lst1;
    }
}

public class Foo2: HomeDevices<AllFoo2>
{
    public Foo2()
    {
        type = "foo2";
    }

    public override List<AllFoo2> GetDeviceData(string jsonResult)
    {
        var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo2>>(jsonResult);
        var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
        return lst1;
    }
}

我的问题是,有没有更简单的方法使用抽象 classes 来做到这一点?我可以直接将我的 "GetAllDevices" class 转换为抽象 class 并继承它并反序列化到它并创建一个通用列表吗?

如果我正确理解您的问题,这应该有所帮助。如果您有任何疑问或它不能按您的需要工作,请告诉我。我在没有测试的情况下很快就把它放在一起了。

类型 属性 的定义方式可以改进,但我保留了它的原样。

public class MyApplication
{
    public void DoWork()
    {
        string json = getJSON();
        DeviceTypeOne foo1 = new DeviceTypeOne();
        DeviceTypeTwo foo2 = new DeviceTypeTwo();
        IList<DeviceTypeOne> foo1Results = foo1.GetDeviceData(json); // calls GetDeviceData extension method
        IList<DeviceTypeTwo> foo2Results = foo2.GetDeviceData(json); // calls GetDeviceData extension method
    }        
}

// implemented GetDeviceData as extension method of DeviceBase, instead of the abstract method within DeviceBase,
// it's slightly cleaner than the abstract method
public static class DeviceExtensions
{
    public static IList<T> GetDeviceData<T>(this T device, string jsonResult) where T : DeviceBase
    {
        IEnumerable<T> deviceDataList = JsonConvert.DeserializeObject<IEnumerable<T>>(jsonResult);
        IEnumerable<T> resultList = deviceDataList.Where(x => x.Type.Equals(typeof(T).Name));
        return resultList.ToList();
    }
}

// abstract base class only used to house common properties and control Type assignment
public abstract class DeviceBase : IDeviceData
{
    protected DeviceBase(string type)
    {
        if(string.IsNullOrEmpty(type)) { throw new ArgumentNullException(nameof(type));}

        Type = type; // type's value can only be set by classes that inherit and must be set at construction time
    }
    [JsonProperty("_id")]
    public string Id { get; set; }
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("type")]
    public string Type { get; private set;} 
    [JsonProperty("actions")]
    public DeviceAction[] Actions { get; set; }
}

public class DeviceTypeOne : DeviceBase
{
    public DeviceTypeOne() : base(nameof(DeviceTypeOne))
    {
    }
}

public class DeviceTypeTwo : DeviceBase
{
    public DeviceTypeTwo() : base(nameof(DeviceTypeTwo))
    {
    }
}

// implemented GetAllDevices class as IDeviceData interface
public interface IDeviceData
{
    string Id { get; set; }
    string Name { get; set; }
    string Type { get; }
    DeviceAction[] Actions { get; set; }
}

// renamed and relocated class Action to DeviceAction
public class DeviceAction
{
    public string Id { get; set; }
    public DeviceActionDefinition DeviceActionDefinition { get; set; }
}

// renamed and relocated Action_Def to DeviceActionDefinition
public class DeviceActionDefinition
{
    public string Id { get; set; }
    public string Name { get; set; }
}

将方法 GetDeviceData() 的实现移动到基础 class.

应该很简单

为此,您需要在 T 上添加约束,以便编译器更多地了解基本类型。您还需要实现一个构造函数来填充您使用的具体类型的 type 字符串。这是确保值始终被填充的必要措施,因为它用于相关方法中的比较:

public abstract class HomeDevices<T> where T: GetAllDevices
{
    public HomeDevices(string concreteType)
    {
        type = concreteType;
    }

    public string type { get; set; }
    public string _id { get; set; }
    public List<AllFoo1> lstfoo1 { get; set; }
    public List<AllFoo2> lstfoo2 { get; set; }

    //This method is now generic and works for both.
    public List<T> GetDeviceData(string jsonResult)
    {
        var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonResult);
        var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
        return lst1;
    }
}

希望对您有所帮助。