InvalidCastException,而upcasting没有编译错误

本文关键字:编译 错误 upcasting InvalidCastException | 更新日期: 2023-09-27 18:23:44

我主要想做的是将从web服务中获得的对象转换为与我的实体框架对象兼容的对象。我想通过创建一个接口来实现这一点,该接口既应用于web服务对象;EF对象。这样我就可以很容易地从一种类型转换到另一种类型。在这一点上,我有以下对象:A、A1、B和接口IAB。

我没有遇到的问题是,当我从对象A向A1进行上转换时,我会得到一个运行时错误,但没有编译错误。我想知道为什么我的推荐不被接受?

public class A
{
  //Has variables & Properties
}
public class A1 : A, IAB
{
  //Has some properties
}

注意:我需要创建A1,因为扩展部分类A为web服务创建了序列化问题。因此,这似乎是最好的解决方案。

当联系该服务时,我要求提供一份a对象的列表,然后想将它们升级到A1。稍后我将把它们铸造成B.

我试着投射这样的物体:

 List<A1> allA1 = new List<A1>();
 foreach (A item in retrievedListOfA)
 {      
     allA1.Add((A1)item); 
 }

由于我没有遇到任何编译错误,所以我发现出现这个错误很奇怪。如果我检查类型"a是A1",那么它永远不会进入if语句。

有人能向我指出为什么这会造成问题吗?是因为对象A来自web服务吗?

注意:如果这种将对象从一个对象"移植"到另一个对象的方法完全荒谬,请给我一些指导。这是我第一次尝试这样的事情。

InvalidCastException,而upcasting没有编译错误

你不会得到任何编译错误,因为(A1)项,你是在对编译器说,我知道我在做什么,所以闭嘴。

因此,如果retrievedListOfA是As和A1的集合,那么您将每个a强制转换为A1(实际上是一个a),然后调用A1方法,它就会爆炸。

有很多移植方法,例如转换器,铸造不是其中之一。

Tony Hopkinson的回答是正确的,说明了您得到当前错误的原因。但是,它目前并没有解决你暗示的更大的问题

报价:Oxillery

注意:如果这种将对象从一个对象"移植"到另一个对象的方法完全荒谬请给我一些应该怎么做的指示。这是我第一次尝试像这样的东西。

看起来您正在接收一个序列化类实例的集合(来自web服务),并希望将它们变成实体框架兼容的对象。我认为您的问题是因为实例的序列化和反序列化之间存在不一致性。

采用以下简单类(我们想要的实体框架实体):

public class Dog
{
    /// <summary>
    /// The unique ID of this dog, aka the number printed on the dog's implanted microchip.
    /// </summary>
    [Key]
    public int Id { get; set; }
    public DateTime Birthday { get; set; }
    public string Name { get; set; }
    /// <summary>
    /// The embarassing number of homeworks shredded.
    /// </summary>
    public long ShreddedHomeworks { get; set; }
}

根据您的声明,您正在从web服务接收某种其他对象,您希望将其转换为Dog。假设您收到的类如下所示:

public class PseudoDog
{
    public DateTime Birthday { get; set; }
    public string Name { get; set; }
    public int Legs { get; set; }
}

请注意,就序列化Pseudog和将其反序列化为Dog而言,这两个类不是直接兼容的。我故意让Pseudog有"Legs"作为属性,Dog有"ShreddedHomeworks",这样在没有操作的情况下,它们就无法转换。

如何转换它们的基础来自Web API关于数据传输对象(DTO)及其使用的教程。继续上面的例子,用于将Pseudog转换为Dog的类如下所示:

using System.Runtime.Serialization;
[DataContract]
public class DogDTO
{
    #region Static Methods
    public static Dog ToDog(DogDTO dto)
    {
        // if the data transfer object is null
        // we cannot make a Dog from it.
        if (dto == null)
        {
            return null;
        }
        Dog dog = new Dog();
        // We can be sure of what these values are intended to be.
        dog.Name = dto.Name;
        dog.Birthday = dto.Birthday;
        return dog;
    }
    public static DogDTO CreateFrom(Dog dog)
    {
        if (dog == null)
        {
            return null;
        }
        DogDTO dto = new DogDTO();
        dto.Name = dog.Name;
        dto.Birthday = dog.Birthday;
    }
    #endregion
    [DataMember]
    public DateTime Birthday { get; set; }
    [DataMember]
    public string Name { get; set; }
}

DogDTO的有趣部分是底部的两个属性(生日名称),它们具有DataMember属性。这意味着DogDTO类可以使用DataContractSerializer进行序列化和反序列化。

把所有的部分放在一起,整个过程看起来是这样的:

  1. 某个客户端生成一个名为"Fido"的PseudoDog实例
  2. 客户端将"Fido"(到XML、JSON、二进制等)序列化到名为"seriadog.XML"的文件中
  3. 客户端向Web服务发送"serialdog.xml"文件
  4. 接收"seriadog.xml"的Web服务将其反序列化为DogDTO实例(名为"FidoDTO")
  5. 您的方法调用DogDTO.ToDog(FidoDTO),它返回一个名为"myFido"的新Dog实例
  6. 您现在可以使用Dog实例"myFido",因为它是一个实体框架实体

成功地,转换如下:

Web Service object --> object DTO --> Entity Framework compliant object

在以下假设下,

类型A-来自web服务的实例的类型

类型A1-当前转换实例的类型

类型B-实体框架使用的实例的类型

类型A_DTO-数据传输对象的类型

无论你有这个代码在哪里,你都应该进行以下更改:

List<A1> allA1 = new List<A1>();
foreach (A item in retrievedListOfA)
{      
     allA1.Add((A1)item); 
}

我会用这个来代替它:

List<B> allB = new List<B>();
foreach (A_DTO dto in retrievedListofA_DTO)
{
    allB.Add(A_DTO.ToB(dto));
}