InvalidCastException,而upcasting没有编译错误

时间:2013-07-18 16:07:37

标签: c# web-services entity-framework casting

我基本上要做的是将从Web服务获取的对象转换为与我的Entity Framework对象兼容的对象。我通过创建一个接口来实现这一点,这两个接口都应用于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); 
 }

由于我没有得到任何编译错误,我发现我收到此错误很奇怪。如果我检查类型&#34; A是A1&#34;然后它永远不会进入if语句。

有人能指出我为什么会出现问题吗?是因为对象A来自Web服务吗?

注意:如果采用此方法&#34;移植&#34;从一个到另一个的对象是完全荒谬的,请给我一些指示如何做。这是我第一次尝试这样的事情。

2 个答案:

答案 0 :(得分:2)

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

因此,如果retrieveListOfA是As和A1的集合,那么每次投射到A1的A,实际上是A,然后调用A1方法就会爆炸。

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

答案 1 :(得分:1)

Tony Hopkinson's answer关于您获得当前错误的原因是正确的。但是,它目前没有解决您提示的更大问题。

  

引用: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; }
}

请注意,这两个类在序列化PseudoDog并将其反序列化为Dog方面不是直接兼容。我故意让PseudoDog把'Legs'作为一个属性而Dog有'ShreddedHomeworks',这样就可以不经过操作而无法转换。

如何转换它们的基础来自Web API tutorial关于数据传输对象(DTO)及其使用。继续上面的例子,用于将PseudoDog转换为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,二进制等)序列化为名为'serialdog.xml'的文件。
  3. 客户端向webservice发送'serialdog.xml'文件。
  4. 接收'serialdog.xml'的web服务将其反序列化为DogDTO实例(名为'FidoDTO')
  5. 您的方法调用DogDTO.ToDog(FidoDTO),它返回一个名为“myFido”的新Dog实例。
  6. 您现在可以使用Dog实例'myFido',因为它是实体框架实体。
  7. 简而言之,转换是这样的:

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