C# 通用列表<;T>;如IEnumerable<;对象>;

C# 通用列表<;T>;如IEnumerable<;对象>;,c#,casting,ienumerable,generic-list,C#,Casting,Ienumerable,Generic List,我正在尝试将列表强制转换为IEnumerable,以便验证不同的列表是否为null或空: 假设myList是一个列表。然后在我想要的调用方代码中: Validator.VerifyNotNullOrEmpty(myList as IEnumerable<object>, @"myList", @"ClassName.Meth

我正在尝试将列表强制转换为IEnumerable,以便验证不同的列表是否为null或空:

假设myList是一个列表。然后在我想要的调用方代码中:

       Validator.VerifyNotNullOrEmpty(myList as IEnumerable<object>,
                                     @"myList",
                                     @"ClassName.MethodName");
Validator.VerifyNotNullOrEmpty(我的列表为IEnumerable,
@“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);

        }
    }
public static void VerifyNotNullOrEmpty(IEnumerable-theEnumerable,
字符串的枚举名,
字符串(验证位置)
{
字符串errMsg=VerifyingPosition+“”+TheEnumerableName;
if(可枚举==null)
{
errMsg+=@“为空”;
Assert(false);
抛出新的ApplicationException(errMsg);
}
else if(theEnumerable.Count()==0)
{
errMsg+=@“为空”;
Assert(false);
抛出新的ApplicationException(errMsg);
}
}

然而,这是行不通的。它可以编译,但其可枚举性为空!为什么?

假设您的目标至少是framework 3.0:

使用扩展名强制转换为泛型
IEnumerable

var myEnumerable = myList.Cast<object>();
在方法内部,使用foreach或
theEnumerable.Cast().Count()检查是否为空


通过这种方式,您不必每次都对IEnumerable进行强制转换,因为列表实现了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);

    }
}
public static void VerifyNotNullOrEmpty(此IEnumerable可枚举,
字符串的枚举名,
字符串(验证位置)
{
字符串errMsg=VerifyingPosition+“”+TheEnumerableName;
if(可枚举==null)
{
errMsg+=@“为空”;
Assert(false);
抛出新的ApplicationException(errMsg);
}
else if(theEnumerable.Count()==0)
{
errMsg+=@“为空”;
Assert(false);
抛出新的ApplicationException(errMsg);
}
}
您应该能够通过以下方式调用它:

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

myList.VerifyNotNullOrEmpty("myList", "My position");
var myList=新列表
{
“测试1”,
“测试2”
};
myList.VerifyNotNullOrEmpty(“myList”、“我的位置”);
您还可以稍微改进实现:

 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));

    }
}
public static void VerifyNotNullOrEmpty(此IEnumerable items,
字符串名,
字符串验证位置)
{
if(items==null)
{
Assert(false);
抛出新的NullReferenceException(string.Format(“{0}{1}为null.”,verifyingPosition,name));
}
else如果(!items.Any())
{
Assert(false);
//您可能希望使用比此更好的(自定义?)异常-EmptyEnumerableCeption或类似的异常?
抛出新的ApplicationException(string.Format(“{0}{1}为空。”,verifyingPosition,name));
}
}
IEnumerable
不是
IEnumerable
的超类型,因此它也不是
列表的超类型。请参阅,以获得关于为什么会出现这种情况的简要概述(关于Java,但概念是相同的)。顺便说一句,这个问题已经在C#4.0中得到了解决,它

您没有发现此错误的原因是您使用了
x作为t
,而您本应使用普通强制转换(
(t)x
),请参阅。由此产生的
InvalidCastException
会指出您的错误。(事实上,如果类型关系正确(即如果
IEnumerable
List
的超类型),则根本不需要强制转换。)

要解决您的问题,请将您的方法设置为泛型,以便它接受
IEnumerable
而不是
IEnumerable
,并完全跳过转换

 public static void VerifyNotNullOrEmpty<T>(IEnumerable<T> theIEnumerable,
                                            string theIEnumerableName,
                                            string theVerifyingPosition) { ... }
public static void VerifyNotNullOrEmpty(IEnumerable-theEnumerable,
字符串的枚举名,
字符串验证位置){…}

不起作用:-(调用者现在调用:Validator.VerifyNotNullOrEmpty(myList.Cast()),…被调用方仍然将IEnumerable theEnumerable作为null接收。您确定myList不是null吗?这一个可能更好-它演示了如何编写通用扩展方法。当然,代码很奇怪-在
errMsg
中添加文本在这里是无用的,但这不是重点。此外,我要注意
Count()
可能会迭代整个集合,这可能不是所需的。我更喜欢
.Any()
检查是否有可用的项目,尽管这可能也有副作用。我同意errMsg,但我并不想更改他的实际实现,因为只要更改签名就可以满足他的需要……我的错误-错误消息转到新的异常,因此它会做些什么。遗漏了那一位:P。仍然有两个不同的类型首选异常PE。在这种情况下,您不能强制转换
(IEnumerable)myList
@Kobi:是的,正是我的观点:如果您使用
(IEnumerable)myList
,您会得到一个
InvalidCastException
,并立即知道您使用了错误的类型。如果您将
myList用作IEnumerable
,您会想知道为什么结果为空(“myList是否为空?强制转换是否失败?”).好的。我误解了你的意思;你似乎建议在这里使用铸造。@Kobi:没问题,谢谢你的反馈。我更新了我的答案来澄清这一点。这些答案有帮助吗?@Dave-Oops。对不起。回答得很好。接受Heinzi的答案是因为它更关注我的代码为什么不起作用,但你的答案清楚地向我解释了什么应该起作用。Th脚踝!
 public static void VerifyNotNullOrEmpty<T>(IEnumerable<T> theIEnumerable,
                                            string theIEnumerableName,
                                            string theVerifyingPosition) { ... }