【问题标题】:How can I create a method that has a smiliar functionality as the new "?." operator? [duplicate]如何创建与新“?”具有相似功能的方法。操作员? [复制]
【发布时间】:2016-01-07 01:06:37
【问题描述】:

使用 C# 6,我们可以使用新的 ? 来访问属性和方法,而无需检查每个属性和方法是否为空。是否可以使用表达式编写具有类似功能的方法?

例如,我必须使用奇怪的对象结构(来自我们无法更改的第 3 方库)。访问某些属性通常需要很长的点链:

rootObject.Services.First().Segments.First().AnotherCollection.First().Weight;

rootObject 之后的任何对象都可以是null。我宁愿不要在它周围加上try/catch。单独检查每个属性也是很多工作。所以我想知道是否可以将它传递给采用表达式并遍历每个属性并在那里检查其值的方法:

var value = PropertyHelper.GetValue(() => rootObject.Services.First().Segments.First().AnotherCollection.First().Weight);

我猜它的签名应该是这样的:

public static T GetValue<T>(Expression<Func<T>> expression)
{
    // analyze the expression and evaluate each property/method
    // stop when null or return the value
}

我不确定表达式是否能够完成我将要做的事情,在我开始实验之前,我想问问它是否可能。

【问题讨论】:

  • 他们将其添加为运算符是有原因的。这是可能的,但它比C# 6 运算符使用起来要笨重得多。在处理 C# 运算符能够解决的不可为空的类型方面也存在一些问题(而且您永远无法解决)。
  • 好吧,你可以创建(子类化)一个ExpressionVisitor 来检查成员访问、调用等,并注入(到重写的表达式中)检查,但是......这是很多反思和很多访问,然后你要么需要Compile()它(添加元编程)或添加甚至更多反射以在运行时评估树......似乎有很多开销跨度>
  • @MarcGravell 是的,尽管如果有问题的代码不在应用程序对性能特别敏感的部分,或者不经常调用,或者编译的委托可以重用,那么性能可能不会糟糕到可以排除解决方案。
  • @Servy 我认为另一个问题也差不多回答了我的问题,而且我不知道如何以不同的方式表述它,这就是我可能没有找到它的原因。我会研究它并尝试一些东西。谢谢。
  • @MarcGravell 如果可行,那我就开始工作 ;-) 我用另一个问题来寻找灵感。

标签: c# reflection lambda


【解决方案1】:
void Main()
{
    var foo = new Foo();

    var qux = NullPropertyExtension.GetValue(() => foo.Bar.Qux);

    Console.WriteLine(qux);


}

public class Foo
{
    public Foo Bar { get; set; }
    public string Qux {get;set;}
}

// Define other methods and classes here
public static class NullPropertyExtension
{
    public static TValue GetValue<TValue>(Expression<Func<TValue>> property)
    {
        var visitor = new Visitor();
        var expression = visitor.Visit(property.Body);
        var lambda = Expression.Lambda<Func<TValue>>(expression);

        var func = lambda.Compile();
        return func();
    }

    private class Visitor : System.Linq.Expressions.ExpressionVisitor
    {
        protected override Expression VisitMember(MemberExpression node)
        {
            var isNotNull = Expression.NotEqual(node.Expression, Expression.Constant(null));
            return Expression.Condition(
                isNotNull,
                node,
                Expression.Constant(null, node.Type));

        }
    }
}

【讨论】:

  • 哇,这么 simple 或者更短 ;-) 但对我来说仍然很神奇。我需要研究它。谢谢。
  • @t3chb0t 请注意,此类仅处理您尝试从中获取属性/字段的对象上的空值。要使.First() 工作,您需要覆盖VisitCallMethod 方法(注意静态方法)。
  • 甚至是null作为参数的方法是合法的。
  • 太好了,谢谢你的提示。我需要一些时间来完全理解它,但如果你有一些可以使用的东西,这是一个好的开始:-) 我还计划记录路径以便以后能够记录它,以便我知道它在哪里失败(null 在哪里)。这在 C# 6 中是不可能的,所以我一定会坚持这个解决方案。
  • @t3chb0t 我建议您下载 LinqPad 以在每个步骤中查看表达式树。这对我学习表达式树元编程很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多