任何IEnumerable的C#EmptyIfFull扩展返回空的派生类型
假设null和空集合是等价的,我正在尝试为IEnumerable类型编写一个扩展方法,以返回派生类型的空集合,而不是null。这样我就不必到处重复null检查,也不必强制转换IEnumerable back e、 g任何IEnumerable的C#EmptyIfFull扩展返回空的派生类型,c#,C#,假设null和空集合是等价的,我正在尝试为IEnumerable类型编写一个扩展方法,以返回派生类型的空集合,而不是null。这样我就不必到处重复null检查,也不必强制转换IEnumerable back e、 g List methodReturningWillist() { ... } Foo[]方法返回fooarray() { ... } 空条() { List List=MethodReturning愚人(); Foo[]arr=MethodReturningFooArray().Em
List methodReturningWillist()
{
...
}
Foo[]方法返回fooarray()
{
...
}
空条()
{
List List=MethodReturning愚人();
Foo[]arr=MethodReturningFooArray().EmptyIfNull();
}
公共静态类扩展
{
公共静态T EmptyIfNull(此T iEnumerable)
其中T:IEnumerable,new()
{
var newTypeFunc=Expression.Lambda(Expression.New(typeof(T))).Compile();
返回iEnumerable==null?newTypeFunc():iEnumerable;
}
}
这个扩展似乎很有效,但有人看到任何陷阱吗?我应该这样改进它
public static class Extension
{
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> iEnumerable)
{
return iEnumerable ?? Enumerable.Empty<T>();
}
}
公共静态类扩展
{
公共静态IEnumerable EmptyIfNull(此IEnumerable IEnumerable)
{
返回iEnumerable??Enumerable.Empty();
}
}
或者用C#6更好
公共静态类扩展
{
公共静态IEnumerable EmptyIfNull(此IEnumerable IEnumerable)
=>iEnumerable??Enumerable.Empty();
}
是的,在这种情况下它会断开:
IEnumerable<int> test = null;
var result = test.EmptyIfNull();
IEnumerable测试=null;
var结果=test.EmptyIfNull();
您可以这样解决它:
public static class Extension
{
public static List<T> EmptyIfNull<T>(this List<T> list)
{
return list ?? new List<T>();
}
public static T[] EmptyIfNull<T>(this T[] arr)
{
return arr ?? new T[0];
}
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> enumerable)
{
return enumerable ?? Enumerable.Empty<T>();
}
}
公共静态类扩展
{
公共静态列表EmptyIfFull(此列表)
{
返回列表??新列表();
}
公共静态T[]emptyIfFull(此T[]arr)
{
返回arr??新T[0];
}
公共静态IEnumerable EmptyIfNull(此IEnumerable可枚举)
{
返回enumerable??enumerable.Empty();
}
}
您需要重载以确保返回的集合类型与以前相同
下面是一个无法通过返回相同集合类型工作的示例:
public abstract class MyAbstractClass : IEnumerable<int>
{
private List<int> tempList = new List<int>();
public IEnumerator GetEnumerator()
{
return tempList.GetEnumerator();
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return tempList.GetEnumerator();
}
}
MyAbstractClass myClass = null;
MyAbstractClass instance = myClass.EmptyIfNull();
公共抽象类MyAbstractClass:IEnumerable
{
私有列表模板列表=新列表();
公共IEnumerator GetEnumerator()
{
返回templast.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回templast.GetEnumerator();
}
}
MyAbstractClass myClass=null;
MyAbstractClass实例=myClass.EmptyIfNull();
在不知道子类的情况下,我们不可能在这里返回MyAbstractClass
。对于空引用,如果没有猜测,这是不可能的。此外,当类没有默认构造函数时会发生什么?进入危险区域
您需要一个catch-all
IEnumerable
返回,并让用户强制转换它,或者提供重载,如我在上面所示,一个获得泛型参数的方法(限制为类,因为我将创建此类型的实例)。然后在运行时定义一个默认对象,并检查参数接收到的对象是否为null,如果该对象为null,则返回在运行时实例化的对象,否则返回参数传递的对象本身
我希望这有帮助
public static T EmptyIfNull<T>(this T obj) where T : class
{
var objNotNull = Activator.CreateInstance(typeof(T));
if (obj == null)
return objNotNull as T;
return obj;
}
公共静态T EmptyIfNull(此T对象),其中T:class
{
var objNotNull=Activator.CreateInstance(typeof(T));
if(obj==null)
将objNotNull返回为T;
返回obj;
}
单元测试:
IEnumerable和IEnumerable不是一回事。每次调用
EmptyIfNull
时,您都在编译一个新方法。您可以简单地执行返回iEnumerable==null?Activator.CreateInstance():iEnumerable代码>出于性能原因,我避免使用Activator。编译后的方法可以缓存,但这部分不是主要关注的问题。我意识到这是一个老问题,但我最近被ping了一下。我注意到现在您添加了:new()约束,该方法可以是returnIEnumerable??new T()
@Rob我当时没有意识到这一点。我相信这应该是答案(没有测试过)。如果变量为空,代码不会中断,他会先检查变量是否为空。@AlbertoMonteiro不,它中断是因为类型是IEnumerable
,无法构造是的,忘记了这个细节。这是最好的方法,回答很好Rob@罗布明白了。。。这对我的需求没关系——只要它事先告诉你。请注意,正如所示,这段代码与OP的代码非常不同——它只适用于IEnumerable
(这确实是大多数代码应该使用的),但对于文章中显示的保留集合类型的测试用例,它失败了(这是否是个好主意可以单独讨论)。添加一些解释和答案,说明此答案如何帮助OP解决当前问题
public abstract class MyAbstractClass : IEnumerable<int>
{
private List<int> tempList = new List<int>();
public IEnumerator GetEnumerator()
{
return tempList.GetEnumerator();
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return tempList.GetEnumerator();
}
}
MyAbstractClass myClass = null;
MyAbstractClass instance = myClass.EmptyIfNull();
public static T EmptyIfNull<T>(this T obj) where T : class
{
var objNotNull = Activator.CreateInstance(typeof(T));
if (obj == null)
return objNotNull as T;
return obj;
}