C# NET 3.5/4.0中的空条件运算符模拟,与2012/2013相比?
在我的代码中,我必须访问调用多个属性getter的值:C# NET 3.5/4.0中的空条件运算符模拟,与2012/2013相比?,c#,linq,nullable,null-conditional-operator,C#,Linq,Nullable,Null Conditional Operator,在我的代码中,我必须访问调用多个属性getter的值: IFoo1 a = objA.Prop1.Value; IFoo2 b = objB.Prop2.Prop3.Value; IFoo3 c = objC.Prop4.Prop5.Prop6.Value; 每个属性都可以为null。因此,要访问每个值,我必须使用嵌套if块: IFoo2 b = null; if(objB.Prop2!=null) { if(objB.Prop2.Prop3!=null) {
IFoo1 a = objA.Prop1.Value;
IFoo2 b = objB.Prop2.Prop3.Value;
IFoo3 c = objC.Prop4.Prop5.Prop6.Value;
每个属性都可以为null。因此,要访问每个值,我必须使用嵌套if块:
IFoo2 b = null;
if(objB.Prop2!=null)
{
if(objB.Prop2.Prop3!=null)
{
b = objB.Prop2.Prop3.Value;
}
}
如何改进此代码以减少if块的数量?我是否可以使用任何lambda表达式、LINQ、IExpression等以某种方式将其替换为:
ifoo2b=GetVal(objB.Prop2.Prop3.Value)
所有的PropX都是不同类型的,我有数百个这样的属性。
我必须使用.NET3.5或至少.NET4.0。我不能使用任何更高版本
重要编辑:
我还必须使用Visual Studio 2012和2013。我无法确定VS 2015的目标。.NET 4.6现在有一个?。解决这个问题的运算符 这允许你这样写 IFoo3 c=objC?.Prop4?.Prop5?.Prop6?.Value
您可以通过创建一个helper函数来解决这个问题,但是代码的清晰性和简单性无法达到这一点。如果可能的话,升级以获得该功能。您可能能做的最好的方法是使用化合物
If
条件,如
IFoo2 b = null;
if(objB.Prop2 != null && objB.Prop2.Prop3 != null)
{
b = objB.Prop2.Prop3.Value;
}
(或)使用三元运算符
IFoo2 b = (objB.Prop2 != null && objB.Prop2.Prop3 != null) ? objB.Prop2.Prop3.Value : null;
这样就可以了,但速度很快而且很脏。一些明显的缺陷:
对于表达式a.b.c-我们调用'a',然后调用'a.b',然后调用'a.b.c',每次都检查null。我们应该存储上一次调用的返回,并修改成员表达式以对结果进行操作。只有当成员访问非常昂贵时才是真正的问题,否则它相当于如果(a!=null&&a.b!=null&&a.b.c!=null)返回a.b.c.d代码>这是一种相当常见的模式
它只适用于成员表达式
不幸的是,您需要C#6来使用空条件运算符(?。
)
但是,可以使用以下扩展方法对其进行模拟:
static class Extensions
{
public static TReturn NCR<T, TReturn>(this T instance, Func<T, TReturn> getter)
where T : class
where TReturn : class
{
if (instance != null)
return getter(instance);
return null;
}
public static TReturn NCR<T, TReturn>(this T? instance, Func<T, TReturn> getter)
where T : struct
where TReturn : class
{
if (instance != null)
return getter(instance.Value);
return null;
}
public static TReturn? NCV<T, TReturn>(this T instance, Func<T, TReturn> getter)
where T : class
where TReturn : struct
{
if (instance != null)
return getter(instance);
return null;
}
public static TReturn? NCV<T, TReturn>(this T? instance, Func<T, TReturn> getter)
where T : struct
where TReturn : struct
{
if (instance != null)
return getter(instance.Value);
return null;
}
}
(如果要获取的属性返回值类型,请使用NCV而不是NCR)
它仍然太冗长,但至少更容易看到代码在做什么。请查看此处的学生类:,我有同样的问题。您使用的是哪个版本的VS?如果是VS2015,您可以使用C#6 null条件运算符,即使是针对.NET 3.5或4.0,我也必须使用.NET 3.5或.NET 4.0。新运算符与C#编译器绑定,而不是.NET。(它基本上会发出所有通常“手动”执行的错误检查代码。)不管使用哪个.NET版本,只要使用的是C#6编译器,而不是.NET 4.6,它的C#6.0,因为它是一个组件特性nit CLR。有没有可能在VS 2012或至少2013中模拟空条件运算符?您正在运行时编译动态方法,然后使用反射调用它们,而不使用任何缓存。这是一个很好的解决方案,但应该非常谨慎地使用。性能影响将在10000倍或更慢的范围内。
var tmp = new classA();
var res = GetOrNull(() => tmp.Prop1.Prop2);
res.Dump(); //Gives null
tmp.Prop1 = new classA.classB();
tmp.Prop1.Prop2 = new classA.classB.classC();
res = GetOrNull(() => tmp.Prop1.Prop2);
res.Dump(); //returns object of type `classC`
static class Extensions
{
public static TReturn NCR<T, TReturn>(this T instance, Func<T, TReturn> getter)
where T : class
where TReturn : class
{
if (instance != null)
return getter(instance);
return null;
}
public static TReturn NCR<T, TReturn>(this T? instance, Func<T, TReturn> getter)
where T : struct
where TReturn : class
{
if (instance != null)
return getter(instance.Value);
return null;
}
public static TReturn? NCV<T, TReturn>(this T instance, Func<T, TReturn> getter)
where T : class
where TReturn : struct
{
if (instance != null)
return getter(instance);
return null;
}
public static TReturn? NCV<T, TReturn>(this T? instance, Func<T, TReturn> getter)
where T : struct
where TReturn : struct
{
if (instance != null)
return getter(instance.Value);
return null;
}
}
IFoo3 c = objC.NCR(_ => _.Prop4)
.NCR(_ => _.Prop5)
.NCR(_ => _.Prop6)
.NCR(_ => _.Value);