13

FedEx の Web サービス API のインターフェースを書き始めました。私が興味を持っている 3 つの異なる API があります。レート、発送、追跡。SvcUtil.exe を使用してサービス プロキシを生成しています。

異なるサービス エンドポイントは、それぞれ独自の WSDL ファイルで FedEx によって指定されます。各サービス エンドポイントには独自の xml 名前空間があります (例: http://fedex.com/ws/rate/v5およびhttp://fedex.com/ws/ship/v5 )

サービス エンドポイントは、Address、Measurements、Weight、AuthenticationDetail、ClientDetail など、かなりの数の同じタイプを使用します。

ここに問題があります。すべての WSDL ファイルを同時に SvcUtil.exe に提供できます。通常は、同一の型を 1 つの共有型に結合しますが、FedEx のサービスはそれぞれ独自の名前空間にあるため、それらは、その名前空間の下の各 WSDL ファイルでこれらの型を再宣言します。代わりに、名前空間ごとに 1 つの 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に強制する方法はありますか?

4

4 に答える 4

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);
        }
    }
}
于 2009-02-19T01:27:59.727 に答える
1

Addressの独自の実装を作成して演算子のオーバーロードを使用するか、安定した型の1つをプロパティとして使用できます。

一例:以下の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);
    }
}

編集:アプローチは上記の投稿と同じです、実装はすべて別のクラスにあります

于 2009-02-18T20:07:38.547 に答える
1

それらの生成されたクラスは「部分的」として定義されていますか? その場合、別のファイルでそれらを拡張し、インターフェイスを抽出して、すべての Address クラスで実装できるようにすることができます。

于 2009-02-18T20:52:03.743 に答える