Ответ 1
Если типы идентичны, и у вас есть контроль над исходными классами, вы можете определить
Я начал писать интерфейс для API-интерфейсов FedEx webservice. У них есть 3 различных API, которые меня интересуют; Скорость, Корабль и Трек. Я генерирую служебные прокси с помощью SvcUtil.exe.
Различные конечные точки обслуживания определяются FedEx в своих файлах WSDL. Каждая конечная точка обслуживания имеет собственное пространство имен xml (например, http://fedex.com/ws/rate/v5 и http://fedex.com/ws/ship/v5)
Конечные точки службы используют довольно много одинаковых типов, таких как Адрес, Измерения, Вес, АутентификацияDetail, ClientDetail и т.д.
И вот в чем проблема: я могу одновременно предоставить все файлы WSDL для SvcUtil.exe, и обычно он объединяет любые одинаковые типы в один общий тип, но поскольку каждая из служб FedEx находится в их собственных пространства имен, и они обновляют эти типы в каждом файле WSDL под этим пространством имен, в результате чего я получаю адрес Address, Address1 и Address2 для каждого пространства имен.
Чтобы решить эту проблему, теперь я должен запускать каждый WSDL через svcutil отдельно и помещать их каждый в свое собственное пространство имен .NET(например, FedEx.Rate, FedEx.Ship, FedEx.Track). Проблема заключается в том, что теперь у меня есть отдельный тип адреса в каждом пространстве имен (Fedex.Rate.Address, FedEx.Ship.Address).
Это затрудняет обобщение кода, используемого между службами, например методом GetAuthenticationDetail() factory, поэтому мне не нужно повторять этот код в каждом месте, где я использую разные службы.
Есть ли способ в С# для принудительного использования FedEx.Rate.Address для FedEx.Ship.Address?
Если типы идентичны, и у вас есть контроль над исходными классами, вы можете определить
Итак, вот как я реализовал неявные операторы преобразования, используя отражение. SvcUtil создает частичные классы, поэтому я добавил неявный оператор преобразования для каждого направления преобразования, поэтому в код клиента вы можете просто набрать Type1 = Type2
.
В этом фрагменте WebAuthenticationCredentials является свойством WebAuthenticationDetails, поэтому, итерации свойств исходного объекта, если типы arent одинаковы (встроенные), он проверяет имя типов (без пространства имен) и рекурсивно вызывает функцию копирования с этими свойствами.
internal class ReflectionCopy
{
public static ToType Copy<ToType>(object from) where ToType : new()
{
return (ToType)Copy(typeof(ToType), from);
}
public static object Copy(Type totype, object from)
{
object to = Activator.CreateInstance(totype);
PropertyInfo[] tpis = totype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] fpis = from.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
// Go through each property on the "to" object
Array.ForEach(tpis, tpi =>
{
// Find a matching property by name on the "from" object
PropertyInfo fpi = Array.Find(fpis, pi => pi.Name == tpi.Name);
if (fpi != null)
{
// Do the source and destination have identical types (built-ins)?
if (fpi.PropertyType == tpi.PropertyType)
{
// Transfer the value
tpi.SetValue(to, fpi.GetValue(from, null), null);
}
else
{
// If type names are the same (ignoring namespace) copy them recursively
if (fpi.PropertyType.Name == tpi.PropertyType.Name)
tpi.SetValue(to, Copy(fpi.PropertyType, tpi.GetValue(from, null)), null);
}
}
});
return to;
}
}
namespace Rate
{
partial class WebAuthenticationDetail
{
public static implicit operator Ship.WebAuthenticationDetail(WebAuthenticationDetail from)
{
return ReflectionCopy.Copy<Ship.WebAuthenticationDetail>(from);
}
}
partial class WebAuthenticationCredential
{
public static implicit operator Ship.WebAuthenticationCredential(WebAuthenticationCredential from)
{
return ReflectionCopy.Copy<Ship.WebAuthenticationCredential>(from);
}
}
}
namespace Ship
{
partial class WebAuthenticationDetail
{
public static implicit operator Rate.WebAuthenticationDetail(WebAuthenticationDetail from)
{
return ReflectionCopy.Copy<Rate.WebAuthenticationDetail>(from);
}
}
partial class WebAuthenticationCredential
{
public static implicit operator Rate.WebAuthenticationCredential(WebAuthenticationCredential from)
{
return ReflectionCopy.Copy<Rate.WebAuthenticationCredential>(from);
}
}
}
вы можете использовать перегрузку оператора, создав собственную реализацию адреса или используя один из стабильных типов как свойство
один пример: Address1 и Address2 ниже будут вашим Rate.Address и Ship.Address соответственно
class Address1
{
public string name = "Address1";
}
class Address2
{
public string name = "Address2";
}
class GenericAddress
{
public string name = "GenericAddress";
public static implicit operator GenericAddress(Address1 a)
{
GenericAddress p = new GenericAddress(); p.name = a.name; return p;
}
public static implicit operator GenericAddress(Address2 a)
{
GenericAddress p = new GenericAddress(); p.name = a.name; return p;
}
}
class Program
{
static void Main(string[] args)
{
PrintName(new Address1());//prints address1
PrintName(new Address2());//prints address2
}
static void PrintName(GenericAddress a)
{
Console.WriteLine(a.name);
}
}
Изменить: подход такой же, как и сообщение выше, реализация находится в отдельном классе, который все
Являются ли эти сгенерированные классы определенными как "частичные"? Если это так, вы можете расширить их в другом файле и извлечь интерфейс и позволить ему реализовать все классы адресов.