6

クラス Car と派生した SportsCar: Carがあります。次の
ようなものです。

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


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

車を返すメソッドを持つWebサービスがあります。

[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 に基づいて新しい Car を返すことができます。このようにすれば、メソッドの意図が明確に表現されていると思います。

    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

ほんの一刺しですが、これを試しましたか?リターンでキャスト。

[WebMethod]
public Car GetMyCar()
{
    Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
    return (Car)mycar;
}
于 2010-05-12T12:13:18.590 に答える
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

常に「SportsCar」ではなく「Car」としてシリアル化する場合は、 を追加[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 に答える