I'm trying to do cast a List to an IEnumerable, so I can verify that different lists are not null or empty:
Suppose myList is a List < T > . Then in the caller code I wanted:
Validator.VerifyNotNullOrEmpty(myList as IEnumerable<object>,
@"myList",
@"ClassName.MethodName");
The valdiating code would be:
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);
}
}
However, this doens't work. It compiles, but theIEnumerable is null! Why?
IEnumerable<object>
is not a supertype of IEnumerable<T>
, so it is not a supertype of List<T>
either. See question 2575363 for a brief overview of why this is the case (it's about Java, but the concepts are the same). This problem has been solved in C# 4.0, by the way, which supports covariant generics.
The reason why you didn't find this error is because you used x as T
, where you should have been using a normal cast ((T)x
), see question 2139798. The resulting InvalidCastException
would have pointed you at your error. (In fact, if the type relationship were correct (i.e. if IEnumerable<object>
were a supertype of List<T>
), you wouldn't need a cast at all.)
To solve your problem, make your method generic, so that it accepts an IEnumerable<T>
instead of an IEnumerable<object>
, and skip the cast completely.
public static void VerifyNotNullOrEmpty<T>(IEnumerable<T> theIEnumerable,
string theIEnumerableName,
string theVerifyingPosition) { ... }
List implements IEnumerable so you don't need to cast them, you just need to make it so your method accepted a generic parameter, like so:
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);
}
}
You should just be able to call it with:
var myList = new List<string>
{
"Test1",
"Test2"
};
myList.VerifyNotNullOrEmpty("myList", "My position");
You could also improve the implementation slightly:
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));
}
}
Supposing you're targeting at least framework 3.0:
Cast to a generic IEnumerable<object>
using extension:
var myEnumerable = myList.Cast<object>();
EDIT:
anyway I'd suggest you to change your method to get a pure IEnumerable like:
public static void VerifyNotNullOrEmpty(IEnumerable theIEnumerable,
string theIEnumerableName,
string theVerifyingPosition)
and inside the method check if empty using foreach or theIEnumerable.Cast<object>().Count()
In this way you don't have to cast every time to IEnumerable<object>