12

シナリオ:

私は現在、3 つの類似した Web サービスを 1 つの使用可能なクラスに抽象化するレイヤーを作成しています。各 Web サービスは、共通性を共有する一連のオブジェクトを公開します。共通性を利用する一連の中間オブジェクトを作成しました。ただし、レイヤーでは、Web サービス オブジェクトとオブジェクトの間で変換する必要があります。

次のように Web サービスを呼び出す前に、実行時にリフレクションを使用して適切な型を作成しました。

    public static object[] CreateProperties(Type type, IProperty[] properties)
    {
        //Empty so return null
        if (properties==null || properties.Length == 0)
            return null;

        //Check the type is allowed
        CheckPropertyTypes("CreateProperties(Type,IProperty[])",type);

        //Convert the array of intermediary IProperty objects into
        // the passed service type e.g. Service1.Property
        object[] result = new object[properties.Length];
        for (int i = 0; i < properties.Length; i++)
        {
            IProperty fromProp = properties[i];
            object toProp = ReflectionUtility.CreateInstance(type, null);
            ServiceUtils.CopyProperties(fromProp, toProp);
            result[i] = toProp;
        }
        return result;
    }

私のサービス実装の1つからの私の呼び出しコードは次のとおりです。

Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties);
_service.SetProperties(folderItem.Path, props);

したがって、各サービスは、独自の IProperty インターフェイスの実装の背後に隠している、異なる「Property」オブジェクトを公開します。

リフレクション コードは単体テストで機能し、適切な型の要素を持つオブジェクトの配列を生成します。しかし、呼び出しコードは失敗します:

System.InvalidCastException: タイプ 'System.Object[]' のオブジェクトをタイプ 'MyProject.Property[] にキャストできません

何か案は?

含まれているオブジェクトが変換可能である限り、オブジェクトからのキャストは機能するという印象を受けましたか?

4

6 に答える 6

9

基本的に、いいえ。配列の共分散にはいくつかの限られた用途がありますが、どのタイプの配列が必要かを単純に把握しておくことをお勧めします。十分に簡単なジェネリック Array.ConvertAll があります (少なくとも、C# 3.0 ではより簡単です)。

Property[] props = Array.ConvertAll(source, prop => (Property)prop);

C# 2.0 バージョン (意味は同じ) は、目に見えにくいものです。

 Property[] props = Array.ConvertAll<object,Property>(
     source, delegate(object prop) { return (Property)prop; });

または、適切なサイズの新しい Property[] を作成し、手動で (または 経由でArray.Copy) コピーするだけです。

配列の共分散でできることの例として:

Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();

object[] asObj = (object[])props;

ここで、「asObj」はそのままで、Property[]単に としてアクセスできますobject[]。C# 2.0 以降では、ジェネリックは通常、配列の共分散よりも優れたオプションになります。

于 2008-10-17T14:44:39.410 に答える
9

別の答え: ジェネリック。

public static T[] CreateProperties<T>(IProperty[] properties)
    where T : class, new()
{
    //Empty so return null
    if (properties==null || properties.Length == 0)
        return null;

    //Check the type is allowed
    CheckPropertyTypes("CreateProperties(Type,IProperty[])",typeof(T));

    //Convert the array of intermediary IProperty objects into
    // the passed service type e.g. Service1.Property
    T[] result = new T[properties.Length];
    for (int i = 0; i < properties.Length; i++)
    {
        T[i] = new T();
        ServiceUtils.CopyProperties(properties[i], t[i]);
    }
    return result;
}

次に、呼び出しコードは次のようになります。

Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);

ずっときれい:)

于 2008-10-17T14:56:13.617 に答える
5

他の人が言ったように、配列は最初から正しいタイプでなければなりません。他の回答は、実際に本物の object[] を変換する方法を示していますが、Array.CreateInstanceを使用して開始する適切な種類の配列を作成できます。

object[] result = (object[]) Array.CreateInstance(type, properties.Length);

が参照型であると仮定するtypeと、これはうまくいくはずです - 配列は正しい型になりますが、それobject[]を入力するためだけに使用します。

于 2008-10-17T14:45:33.230 に答える
4

そのような配列を変換することはできません-オブジェクトとは異なるオブジェクトの配列を返しています。Array.ConvertAll を試す

于 2008-10-17T14:42:12.973 に答える
1

その通りですが、これは Object 型のコンテナーを他の型のコンテナーにキャストできるという意味ではありません。Object[] は Object と同じではありません (奇妙なことに、Object[] を Object にキャストできます)。

于 2008-10-17T14:42:50.163 に答える
1

C# 2.0 では、ジェネリックを使用せず、コンパイル時に目的の型を知らなくても、リフレクションを使用してこれを行うことができます。

//get the data from the object factory
object[] newDataArray = AppObjectFactory.BuildInstances(Type.GetType("OutputData"));
if (newDataArray != null)
{
    SomeComplexObject result = new SomeComplexObject();
    //find the source
    Type resultTypeRef = result.GetType();
    //get a reference to the property
    PropertyInfo pi = resultTypeRef.GetProperty("TargetPropertyName");
    if (pi != null)
    {
        //create an array of the correct type with the correct number of items
        pi.SetValue(result, Array.CreateInstance(Type.GetType("OutputData"), newDataArray.Length), null);
        //copy the data and leverage Array.Copy's built in type casting
        Array.Copy(newDataArray, pi.GetValue(result, null) as Array, newDataArray.Length);
    }
}

すべての Type.GetType("OutputData") 呼び出しと GetProperty("PropertyName") を、構成ファイルから読み取るコードに置き換えます。

また、ジェネリックを使用して SomeComplexObject の作成を指示します

T result = new T();
Type resultTypeRef = result.GetType();

しかし、ジェネリックを使用する必要はないと言いました。

パフォーマンス/効率を保証するものではありませんが、機能します。

于 2010-07-20T14:39:30.660 に答える