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

时间:2019-08-01 19:36:07

标签: c# json abstract-class generic-list

我有一个Json类“ GetAllDevices()”。我的JSON响应包含一个对象数组/列表,其中每个对象都具有以下公共属性。

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个包含上述所有属性的通用列表。 lstfoo1列表包含所有属性(_id,名称类型和操作),其中type =“ foo1”。同样,lstfoo2是一个List,其中包含上述属性,类型为=“ 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;
    }
}

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

2 个答案:

答案 0 :(得分:2)

如果我正确理解了您的问题,这应该会有所帮助。让我知道您是否有疑问,或者如果您有任何疑问,请联系我们。我很快就将它们组合在一起,无需进行测试。

可以改进Type属性的定义方式,但我还是保留了它。

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; }
}

答案 1 :(得分:1)

将方法GetDeviceData()的实现转移到基类应该足够简单。

为此,您需要在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;
    }
}

我希望有帮助。