6

我有一个类 Car 和一个派生的 SportsCar: Car
像这样的东西:

public class Car
{
    public int TopSpeed{ get; set; }
}


public class SportsCar : Car
{
    public string GirlFriend { get; set; }
}

我有一个带有返回汽车的方法的网络服务,即:

[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 文档时出错。---> System.InvalidOperationException:类型 wsBaseDerived.SportsCar 不是预期的。使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型。

我觉得很奇怪它不能将它序列化为一辆直车,因为 mycar 是一辆汽车。

在我们的 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>

但我真的希望返回基类,而不需要派生类的额外属性等。

如果不创建映射器等,这是否可能?

请说是的;)

4

6 回答 6

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);
    }
于 2010-05-14T11:06:00.853 回答
1

做这个:

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return new Car() {TopSpeed = mycar.TopSpeed};
}

原因是 XMLSerializer 检查对象的 GetType() 类型并期望它与声明的类型相同。

我知道这很痛苦,但我不知道有什么替代方法。

于 2010-05-12T12:42:42.243 回答
0

对要忽略的属性使用XmlIgnoreAttribute 。或者更痛苦的方法是为您的属性实现自定义序列化。

祝你好运。

public class SportsCar : Car
{
  [XmlIgnoreAttribute]
  public string GirlFriend { get; set; }
}
于 2010-05-12T11:55:24.133 回答
0

这里的其他评论和答案让我思考,如果我需要制作 Mapper 方法,那就这样吧:

public class Car: ICloneable
{
    public int TopSpeed{ get; set; }
    public object Clone()
    {
        return new Car() { TopSpeed = this.TopSpeed };
    }

}

和网络方法:

[WebMethod]
public Car GetMyNewCar()
{
    Car mycar = new SportsCar() { GirlFriend = "HiLo", TopSpeed = 300 };            
    return (Car)mycar.Clone();
}

这按预期工作:

<Car>
    <TopSpeed>300</TopSpeed>
</Car>

这违背了在我看来拥有派生对象的目的,但直到有人想出另一个解决方案,这就是我要飞的方式......

于 2010-05-12T13:18:35.240 回答
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>
于 2010-05-12T13:21:41.137 回答
0

只是一个刺,但你试过吗?回程时投。

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return (Car)mycar;
}
于 2010-05-12T12:13:18.590 回答