我有一辆Car和一辆派生的SportsCar:Car
像这样:
public class Car
{
public int TopSpeed{ get; set; }
}
public class SportsCar : Car
{
public string GirlFriend { get; set; }
}
我有一个Web服务,其方法是返回Cars,即
[WebMethod]
public Car GetCar()
{
return new Car() { TopSpeed = 100 };
}
它返回:
<Car>
<TopSpeed>100</TopSpeed>
</Car>
我还有另一种方法可以像这样返回汽车:
[WebMethod]
public Car GetMyCar()
{
Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
return mycar;
}
它编译好了一切,但是在调用它时我得到:
System.InvalidOperationException:生成XML文档时出错。 ---&GT; System.InvalidOperationException:不期望类型为wsBaseDerived.SportsCar。使用XmlInclude或SoapInclude属性指定静态未知的类型。
我觉得很奇怪,因为mycar是一辆汽车所以它无法将其序列化为直车。
在Web的WebMethod上添加XmlInclude会删除错误:
[WebMethod]
[XmlInclude(typeof(SportsCar))]
public Car GetMyCar()
{
Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
return mycar;
}
现在它返回:
<Car xsi:type="SportsCar">
<TopSpeed>300</TopSpeed>
<GirlFriend>JLo</GirlFriend>
</Car>
但我真的想要返回基类, 没有来自派生类的额外属性等。
在没有创建地图制作者等的情况下,这完全可以吗?
请说是;)
答案 0 :(得分:2)
我会在基类中实现一个复制构造函数。
public class Car
{
public int TopSpeed { get; set; }
public Car(Car car)
{
TopSpeed = car.TopSpeed;
}
public Car()
{
TopSpeed = 100;
}
}
public class SportsCar : Car
{
public string GirlFriend { get; set; }
}
然后你可以在GetMyCar方法中根据SportsCar返回一辆新车。我认为这种方式清楚地表达了该方法的意图。
public Car GetMyCar()
{
var sportsCar = new SportsCar { GirlFriend = "JLo", TopSpeed = 300 };
return new Car(sportsCar);
}
答案 1 :(得分:1)
这样做:
[WebMethod]
public Car GetMyCar()
{
Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
return new Car() {TopSpeed = mycar.TopSpeed};
}
原因是XMLSerializer检查对象的GetType()类型,并期望它与声明的对象相同。
我知道这是一种痛苦,但我不知道另一种选择。
答案 2 :(得分:0)
对要忽略的属性使用XmlIgnoreAttribute。或者更痛苦的方法是为你的属性实现custom serialization。
祝你好运。public class SportsCar : Car
{
[XmlIgnoreAttribute]
public string GirlFriend { get; set; }
}
答案 3 :(得分:0)
只是一个刺,但你试过这个吗?投下回报。
[WebMethod]
public Car GetMyCar()
{
Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
return (Car)mycar;
}
答案 4 :(得分:0)
尝试WCF,有[KnownType]。
但是,不知道是否可以使用oldskool SOAP webservices。
答案 5 :(得分:0)
这里的其他评论和答案让我思考,如果我需要制作一个Mapper方法,那就这样吧:
public class Car: ICloneable
{
public int TopSpeed{ get; set; }
public object Clone()
{
return new Car() { TopSpeed = this.TopSpeed };
}
}
和webmethod:
[WebMethod]
public Car GetMyNewCar()
{
Car mycar = new SportsCar() { GirlFriend = "HiLo", TopSpeed = 300 };
return (Car)mycar.Clone();
}
这可以按预期工作:
<Car>
<TopSpeed>300</TopSpeed>
</Car>
这违背了我在视图中使用派生对象的目的,但是直到有人提出另一种解决方案,就像我将要飞行一样......
答案 6 :(得分:0)
如果您希望始终序列化为“Car”而不是“SportsCar”,请为其添加[XmlRoot("Car")]
。
public class Car {
//stuff
}
[XmlRoot("Car")]
public class SportsCar {
//Sporty stuff
}
编辑:像这样使用XmlSerializer:
XmlSerializer ser = new XmlSerializer(typeof(SportsCar));
SportsCar car = new SportsCar()
//stuff
ser.Serialize(Console.out, car)
你应该得到
<Car>
<TopSpeed>300</TopSpeed>
<GirlFriend>JLo</GirlFriend>
</Car>