4

わかりました、私の実際の問題はこれでした:私はIList<T>. に到達したときCopyTo(Array array, int index)、これが私の解決策でした:

void ICollection.CopyTo(Array array, int index)
{
    // Bounds checking, etc here.
    if (!(array.GetValue(0) is T))
        throw new ArgumentException("Cannot cast to this type of Array.");
    // Handle copying here.
}

これは私の元のコードで機能し、引き続き機能します。しかし、それには小さな欠陥があり、テストの構築を開始するまで明らかにされませんでした。具体的には次のようなものです。

public void CopyToObjectArray()
{
    ICollection coll = (ICollection)_list;
    string[] testArray = new string[6];

    coll.CopyTo(testArray, 2);
}

これで、このテストに合格するはずです。ArgumentExceptionキャストできないくらい投げます。なんで?array[0] == null. に設定されている変数をチェックすると、isキーワードは常に false を返しますnull。これは、null デリファレンスの回避など、さまざまな理由で便利です。型チェックのために最終的に思いついたのは次のとおりです。

try
{
    T test = (T)array.GetValue(0);
}
catch (InvalidCastException ex)
{
    throw new ArgumentException("Cannot cast to this type of Array.", ex);
}

これは正確にはエレガントではありませんが、機能します...もっと良い方法はありますか?

4

4 に答える 4

4

これ専用の Type のメソッドがあります。試してください:

if(!typeof(T).IsAssignableFrom(array.GetElementType()))
于 2008-10-04T02:18:23.697 に答える
3

確認する唯一の方法はリフレクションを使用することですが、90% の確率で を使用することでそのコストを回避できますarray is T[]。ほとんどの人は適切に型付けされた配列を渡すので、それで十分です。ただし、念のため、リフレクション チェックを行うコードも常に提供する必要があります。これが私の一般的なボイラープレートの外観です(注:これはメモリからここに書いたので、コンパイルされない可能性がありますが、基本的なアイデアが得られるはずです):

class MyCollection : ICollection<T> {
   void ICollection<T>.CopyTo(T[] array, int index) {
       // Bounds checking, etc here.
       CopyToImpl(array, index);
   }
   void ICollection.CopyTo(Array array, int index) {
       // Bounds checking, etc here.
       if (array is T[]) { // quick, avoids reflection, but only works if array is typed as exactly T[]
           CopyToImpl((T[])localArray, index);
       } else {
           Type elementType = array.GetType().GetElementType();
           if (!elementType.IsAssignableFrom(typeof(T)) && !typeof(T).IsAssignableFrom(elementType)) {
               throw new Exception();
           }
           CopyToImpl((object[])array, index);
       }
   }
   private void CopyToImpl(object[] array, int index) {
       // array will always have a valid type by this point, and the bounds will be checked
       // Handle the copying here
   }
}

編集:わかりました、何かを指摘するのを忘れていました。いくつかの回答では、このコードでは、読み取りelement.IsAssignableFrom(typeof(T))専用として単純に使用されています。また、開発者がこの特定のすべての値が実際にはから派生した型であることを知っており、型の配列を渡す場合に備えて、BCL と同様にを許可する必要があります。typeof(T).IsAssignableFrom(elementType)ICollectionSTS[]

于 2008-10-04T02:47:33.183 に答える
1

List<T>これを使用します:

try
{
    Array.Copy(this._items, 0, array, index, this.Count);
}
catch (ArrayTypeMismatchException)
{
  //throw exception...
}
于 2008-10-04T02:31:18.647 に答える
0

以下は、try / catch とリフレクションの小さなテストです。

object[] obj = new object[] { };
DateTime start = DateTime.Now;

for (int x = 0; x < 1000; x++)
{
    try
    {
        throw new Exception();
    }
    catch (Exception ex) { }
}
DateTime end = DateTime.Now;
Console.WriteLine("Try/Catch: " + (end - start).TotalSeconds.ToString());

start = DateTime.Now;

for (int x = 0; x < 1000; x++)
{
    bool assignable = typeof(int).IsAssignableFrom(obj.GetType().GetElementType());
}
end = DateTime.Now;
Console.WriteLine("IsAssignableFrom: " + (end - start).TotalSeconds.ToString());

リリース モードでの結果の出力は次のとおりです。

Try/Catch: 1.7501001
IsAssignableFrom: 0

デバッグモード:

Try/Catch: 1.8171039
IsAssignableFrom: 0.0010001

結論として、反射チェックを行うだけです。価値がある。

于 2009-02-13T14:49:29.550 に答える