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服务吗?
注意:如果这种将对象从一个对象"移植"到另一个对象的方法完全荒谬,请给我一些指导。这是我第一次尝试这样的事情。
你不会得到任何编译错误,因为(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进行序列化和反序列化。
把所有的部分放在一起,整个过程看起来是这样的:
- 某个客户端生成一个名为"Fido"的PseudoDog实例
- 客户端将"Fido"(到XML、JSON、二进制等)序列化到名为"seriadog.XML"的文件中
- 客户端向Web服务发送"serialdog.xml"文件
- 接收"seriadog.xml"的Web服务将其反序列化为DogDTO实例(名为"FidoDTO")
- 您的方法调用DogDTO.ToDog(FidoDTO),它返回一个名为"myFido"的新Dog实例
- 您现在可以使用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));
}