문제

좋아, 나의 실제 문제는 이것입니다 : 나는 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. 이제 이것은 널리 복제 등을 피하는 등 모든 종류의 이유로 편리합니다. 내 유형 확인을 위해 마침내 내가 생각해 낸 것은 다음과 같습니다.

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

이것은 정확히 우아하지는 않지만 작동합니다 ... 더 좋은 방법이 있습니까?

도움이 되었습니까?

해결책

확실히 확실한 방법은 반사를 사용하는 것이지만 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)) 뿐. 너 ~해야 한다 또한 허용 typeof(T).IsAssignableFrom(elementType), BCL이하는 것처럼, 개발자 가이 특정의 모든 값을 알고있는 경우 ICollection 실제로 유형입니다 S 로부터 나오다 T, 유형의 배열을 통과합니다 S[]

다른 팁

이를 위해 특별히 유형에 대한 방법이 있습니다.

if(!typeof(T).IsAssignableFrom(array.GetElementType()))

List<T> 이것을 사용합니다 :

try
{
    Array.Copy(this._items, 0, array, index, this.Count);
}
catch (ArrayTypeMismatchException)
{
  //throw exception...
}

다음은 시도 / 캐치 대 반사에 대한 약간의 테스트입니다.

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

결론, 단지 반사 검사를하십시오. 그것은 가치.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top