我已经开始为FedEx的webservice API编写一个界面。他们有3种不同的API,我很感兴趣;费率,发货和跟踪。我正在使用SvcUtil.exe生成服务代理。
FedEx在自己的WSDL文件中指定了不同的服务端点。每个服务端点都有自己的xml命名空间(例如http://fedex.com/ws/rate/v5和http://fedex.com/ws/ship/v5)
服务端点确实使用了很多相同的类型,例如Address,Measurements,Weight,AuthenticationDetail,ClientDetail等......
这就是问题所在,我可以同时向SvcUtil.exe提供所有WSDL文件,通常它会将任何相同的类型合并为一个共享类型,但由于FedEx的每个服务都属于他们自己的命名空间,并且他们在该命名空间下的每个WSDL文件中重新声明这些类型,而不是每个命名空间的Address,Address1和Address2。
要解决这个问题,我现在要做的是分别通过svcutil运行每个WSDL,并将它们分别放在自己的.NET命名空间中(例如FedEx.Rate,FedEx.Ship,FedEx.Track)。这个问题是现在我在每个命名空间中都有一个不同的地址类型(Fedex.Rate.Address,FedEx.Ship.Address)。
这使得很难概括像GetAuthenticationDetail()工厂方法之类的服务之间使用的代码,因此我不必在每个使用不同服务的地方重复该代码。
C#中有没有办法将FedEx.Rate.Address强制转换为FedEx.Ship.Address?
答案 0 :(得分:8)
如果类型相同,并且您可以控制源类,则可以在类中定义conversion operator,任何带Rate.Address
的函数也将自动获取{{1} }}。例如:
Ship.Address
我的C#有点生疏,但我希望你明白这一点。
答案 1 :(得分:7)
所以这就是我如何使用反射实现隐式转换运算符。 SvcUtil创建了部分类,因此我为转换的每个方向添加了隐式转换运算符,因此在客户端代码中只需键入Type1 = Type2
。
在这个片段中,WebAuthenticationCredentials是WebAuthenticationDetails的一个属性,所以当迭代源对象的属性时,如果类型不相同(内置函数),它会检查类型的名称(没有命名空间)并递归调用复制函数有这些属性。
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);
}
}
}
答案 2 :(得分:1)
您可以通过创建自己的Address实现或使用其中一个稳定类型作为属性来使用运算符重载
一个例子:下面的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);
}
}
编辑:方法与上面的帖子相同,实现是在一个单独的类中全部
答案 3 :(得分:1)
这些生成的类是否定义为“部分”?如果是这样,您可以将它们扩展到不同的文件中并提取接口,并让它由所有Address类实现。