【问题标题】:C# convert List<baseclass> to List<DerivedClass> [duplicate]C# 将 List<baseclass> 转换为 List<DerivedClass> [重复]
【发布时间】:2018-01-20 04:37:20
【问题描述】:

感谢您的帮助。我已经为此苦苦挣扎了太久了。

我可以通过使用重复的属性列表创建两个单独的模型类来轻松解决这个问题,但我想了解如何使用基类来实现这一点。所以,IntSensorExtSensor 都是 Sensor。从另一个类中,我解析了一个包含所有数据的 json 文件,效果很好。但是,尝试调用返回 List&lt;Sensor&gt; 基类的方法并尝试将其转换为任一子类正在杀死我。我做错了什么......还是有更好的方法?谢谢!

PS:这可能看起来像一个重复的问题,但我尝试了其他解决方案,它们在代码中的“存储库类”中标记为“//在其他 StackOverflow 帖子上看到 - 失败”。

//模型类

public class Device
{
    public string IP { get; set; }   
    public string Name { get; set; }
    public IList<IntSensor> InternalSensors { get; set; }
    public IList<ExtSensor> ExternalSensors { get; set; }
}

public class Sensor
{
    public string Name { get; set; }
    public string ActualTemp { get; set; }
    public string HighTemp { get; set; }
    public string LowTemp { get; set; }
}

public class IntSensor : Sensor {}
public class ExtSensor : Sensor {}

//业务类--解析json

public class ParseJsonData
{
    public static RoomAlertModel GetRoomAlertModel(JObject jsonTree)
    {
        RoomAlertModel model = new RoomAlertModel();
        model.IP = jsonTree["ip"].ToString();
        model.Name = jsonTree["name"].ToString();

        return model;
    }

    public static List<Sensor> GetSensors(JToken jToken)
    {
        var sensors = new List<Sensor>();

        try
        {
            foreach (var item in jToken)
            {
                var s = new Sensor();
                s.Label = item["lab"].ToString();
                s.ActualTemp = item["tf"] != null ? item["tf"].ToString() : "";
                s.HighTemp = item["hf"] != null ? item["hf"].ToString() : "";
                s.LowTemp = item["lf"] != null ? item["lf"].ToString() : "";

                sensors.Add(s);
            }
        }
        catch (Exception)
        {
        }            

        return sensors;
    }
}

//存储库

public class RoomAlertRepository
    {
        internal RoomAlertModel Retreive()
        {
            var filePath = HostingEnvironment.MapPath(@"~/App_Data/RoomAlertsData.json");

            var json = File.ReadAllText(filePath);

            JObject jsonTree = JObject.Parse(json);
            var internalSensorTree = jsonTree["internal_sen"];
            var externalSensorTree = jsonTree["sensor"];

            var model = ParseJsonData.GetRoomAlertModel(jsonTree);

            var baseList = ParseJsonData.GetSensors(internalSensorTree);

            //seen on other StackOverflow Posts -- fails
            var iSensorsTry1 = baseList.Cast<IntSensor>();
            //seen on other StackOverflow Posts -- fails
            var iSensorsTry2 = baseList.ConvertAll(instance => (IntSensor)instance);
            //seen on other StackOverflow Posts -- fails
            var iSensorsTry3 = baseList.OfType<IntSensor>();

            model.InternalSensor = iSensorsTry1.ToList();


            return model;
        }
    }

【问题讨论】:

  • 您遇到了“泛型类型差异”。 List&lt;IntSensor&gt;List&lt;Sensor&gt; 根本不兼容。例如,给定一个List&lt;Sensor&gt;,您可以将ExtSensor 放入其中。然后,如果您被允许强制转换为 List&lt;IntSensor&gt;,那么现在您将得到一个应该只有 IntSensor 元素但有一个 ExtSensor 元素的列表。
  • 请注意,就您的代码中的三个尝试而言:您无法转换您拥有的对象。 Cast&lt;T&gt;() 会抛出异常,OfType&lt;T&gt;() 不会返回任何东西。你可以使用ConvertAll(),但是你的lambda需要创建新对象,而不是尝试从Sensor转换为例如IntSensor。有关您问题的这方面的信息,请参阅第二个标记的副本。
  • 我不同意这是一个重复的问题。尝试其他帖子中的任何解决方案。我不认为他们工作。一个答案是 list.Type of... 不起作用。其他答案也不起作用。用“重复”的答案回答这些主题很容易,但要确保这些重复的答案首先起作用。我可能错了,但我不这么认为。不过感谢您的回复。
  • 此外,这不是继承的基础:ExternalSensor“是”传感器,InternalSensor“是”传感器吗?我认为我可以将其转换为派生类型?
  • 另一个答案“不起作用”只是在您没有正确应用它们的意义上。您的问题的基础假设您正在创建 Sensor 对象。问题中没有任何内容表明您可以首先创建不同类型的对象;您是专门询问有关演员表的问题“这不是继承的基础” - 不,不是您尝试使用它的方式。继承意味着派生类的实例“是”基类的实例;但它不是一条双向街道。

标签: c# asp.net-web-api


【解决方案1】:

在您的GetSensors 方法中,您正在创建基类Sensor 的实例。尝试将它们隐式转换为其他派生类是不可能的。您应该在该方法中使用泛型类型参数并创建实际派生类型的实例。

像这样:(注意where 子句和T 参数的new 约束)

public static List<T> GetSensors<T>(JToken jToken) where T : Sensor, new()
{
    var sensors = new List<T>();

    try
    {
        foreach (var item in jToken)
        {
            var s = new T();
            s.Label = item["lab"].ToString();
            s.ActualTemp = item["tf"] != null ? item["tf"].ToString() : "";
            s.HighTemp = item["hf"] != null ? item["hf"].ToString() : "";
            s.LowTemp = item["lf"] != null ? item["lf"].ToString() : "";

            sensors.Add(s);
        }
    }
    catch (Exception)
    {
    }            

    return sensors;
}

现在这样称呼它:

List<IntSensor> iSensors = ParseJsonData.GetSensors<IntSensor>(internalSensorTree);

【讨论】:

  • 谢谢格雷格!我尝试使用泛型,但无法正确使用。因为我在家,所以我无法测试它,但明天或星期一会。我希望这不会被删除,因为它被标记为重复的问题(我不认为它是重复的)。再次感谢!!
  • Greg,我也尝试了隐式转换,但似乎没有用。能给我举个例子吗。我无法想象我也弄错了。再次感谢!
  • 嗯,我刚试了一下,好像我错了:你不能用隐式转换来解决这个问题。 user-defined conversions to or from a derived class are not allowed
  • 谢天谢地。如果我无法征服它,我就准备放弃一切。哈哈。我不敢相信我遇到了这么多麻烦。再次感谢!
猜你喜欢
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
相关资源
最近更新 更多