Общий список <T>как IEnumerable <object> - PullRequest
3 голосов
/ 20 мая 2010

Я пытаюсь выполнить приведение списка к IEnumerable, чтобы я мог убедиться, что разные списки не являются пустыми или пустыми:

Предположим, что myList является списком . Тогда в коде звонящего я хотел:

       Validator.VerifyNotNullOrEmpty(myList as IEnumerable<object>,
                                     @"myList",
                                     @"ClassName.MethodName");

Код проверки будет:

     public static void VerifyNotNullOrEmpty(IEnumerable<object> theIEnumerable,
                                        string theIEnumerableName,
                                        string theVerifyingPosition)
    {
        string errMsg = theVerifyingPosition + " " + theIEnumerableName;
        if (theIEnumerable == null)
        {
            errMsg +=  @" is null";
            Debug.Assert(false);
            throw new ApplicationException(errMsg);

        }
        else if (theIEnumerable.Count() == 0)
        {
            errMsg +=  @" is empty";
            Debug.Assert(false);
            throw new ApplicationException(errMsg);

        }
    }

Однако, это не работает. Он компилируется, но theIEnumerable имеет значение null! Почему?

Ответы [ 3 ]

6 голосов
/ 20 мая 2010

List реализует IEnumerable, поэтому вам не нужно приводить их, вам просто нужно сделать так, чтобы ваш метод принял универсальный параметр, например:

 public static void VerifyNotNullOrEmpty<T>(this IEnumerable<T> theIEnumerable,
                                    string theIEnumerableName,
                                    string theVerifyingPosition)
{
    string errMsg = theVerifyingPosition + " " + theIEnumerableName;
    if (theIEnumerable == null)
    {
        errMsg +=  @" is null";
        Debug.Assert(false);
        throw new ApplicationException(errMsg);

    }
    else if (theIEnumerable.Count() == 0)
    {
        errMsg +=  @" is empty";
        Debug.Assert(false);
        throw new ApplicationException(errMsg);

    }
}

Вы должны просто иметь возможность позвонить с:

var myList = new List<string>
{
    "Test1",
    "Test2"
};

myList.VerifyNotNullOrEmpty("myList", "My position");

Вы также можете немного улучшить реализацию:

 public static void VerifyNotNullOrEmpty<T>(this IEnumerable<T> items,
                                    string name,
                                    string verifyingPosition)
{
    if (items== null)
    {
        Debug.Assert(false);
        throw new NullReferenceException(string.Format("{0} {1} is null.", verifyingPosition, name));
    }
    else if ( !items.Any() )
    {
        Debug.Assert(false);
        // you probably want to use a better (custom?) exception than this - EmptyEnumerableException or similar?
        throw new ApplicationException(string.Format("{0} {1} is empty.", verifyingPosition, name));

    }
}
5 голосов
/ 20 мая 2010

IEnumerable<object> не является супертипом IEnumerable<T>, поэтому он также не является супертипом List<T>. См. вопрос 2575363 для краткого обзора, почему это так (речь идет о Java, но концепции те же). Эта проблема была решена в C # 4.0, кстати, который поддерживает ковариантные дженерики .

Причина, по которой вы не нашли эту ошибку, заключается в том, что вы использовали x as T, где вы должны были использовать обычное приведение ((T)x), см. вопрос 2139798 . В результате InvalidCastException указал бы на вашу ошибку. (На самом деле, если бы отношение типа было правильным (то есть, если IEnumerable<object> был супертипом List<T>), вам бы вообще не понадобилось приведение.)

Чтобы решить вашу проблему, сделайте ваш метод универсальным, чтобы он принимал IEnumerable<T> вместо IEnumerable<object>, и полностью пропустите приведение.

 public static void VerifyNotNullOrEmpty<T>(IEnumerable<T> theIEnumerable,
                                            string theIEnumerableName,
                                            string theVerifyingPosition) { ... }
4 голосов
/ 20 мая 2010

Предположим, вы нацелены как минимум на фреймворк 3.0:

Приведение к универсальному IEnumerable<object> с использованием расширения:

var myEnumerable = myList.Cast<object>();

EDIT: В любом случае, я бы посоветовал вам изменить свой метод, чтобы получить чистый IEnumerable вроде:

public static void VerifyNotNullOrEmpty(IEnumerable theIEnumerable,
                                        string theIEnumerableName,
                                        string theVerifyingPosition)

и внутри метода проверьте, не пусто ли с помощью foreach или theIEnumerable.Cast<object>().Count()

Таким образом, вам не нужно каждый раз кастовать на IEnumerable<object>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...