У меня есть класс Автомобиль и полученный SportsCar: Автомобиль
Что-то вроде этого:
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;
}
Это компилирует прекрасный и все, но при вызове его я добираюсь:
Система. InvalidOperationException: была ошибка при генерации XML-документа.---> Система. InvalidOperationException: тип wsBaseDerived. SportsCar не ожидался. Используйте атрибут XmlInclude или SoapInclude для определения типов, которые не известны статически.
Я нахожу это странным, что это не может сериализировать это как прямой автомобиль, поскольку mycar является автомобилем.
Добавление XmlInclude на WebMethod ourse удаляет ошибку:
[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>
Но я действительно хочу возвращенный базовый класс без дополнительных свойств и т.д. от производного класса.
Это вообще возможно, не создавая картопостроители и т.д.?
Скажите да ;)
Другие комментарии и ответы заставили меня задуматься, и если мне нужно создать 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>
Это противоречит цели имея производный объект, на мой взгляд, но пока кто-то не предложит другое решение, я буду летать так ...
Сделайте следующее:
[WebMethod]
public Car GetMyCar()
{
Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
return new Car() {TopSpeed = mycar.TopSpeed};
}
Причина в том, что XMLSerializer проверяет тип GetType () объекта и ожидает, что он будет таким же, как объявленный.
Я знаю, что это больно, но не знаю альтернативы.
Либо используйте XmlIgnoreAttribute для атрибутов, которые вы хотите игнорировать. Или еще более болезненным способом было бы реализовать настраиваемую сериализацию для ваших атрибутов.
Удачи.
public class SportsCar : Car
{
[XmlIgnoreAttribute]
public string GirlFriend { get; set; }
}
Просто попытка, но вы пробовали это? Каст на возврат.
[WebMethod]
public Car GetMyCar()
{
Car mycar = new SportsCar() { GirlFriend = "JLo", TopSpeed = 300 };
return (Car)mycar;
}
Попробуйте WCF, есть [KnownType].
Однако не знаю, возможно ли это с помощью старых веб-сервисов SOAP.
Если вы хотите, чтобы он всегда сериализовался как "Car" вместо "SportsCar", добавьте к нему [XmlRoot("Car")]
.
public class Car {
//stuff
}
[XmlRoot("Car")]
public class SportsCar {
//Sporty stuff
}
Edit: Используя 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>
Я бы реализовал конструктор копирования в базовом классе.
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; }
}
Затем вы можете вернуть новый Автомобиль на основе SportsCar в GetMyCar-методе. Я думаю, что это ясно выражает цель метода.
public Car GetMyCar()
{
var sportsCar = new SportsCar { GirlFriend = "JLo", TopSpeed = 300 };
return new Car(sportsCar);
}