Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从属性表达式获取属性的所有者对象_C#_Lambda - Fatal编程技术网

C# 从属性表达式获取属性的所有者对象

C# 从属性表达式获取属性的所有者对象,c#,lambda,C#,Lambda,我正在编写一段代码,它的最终目的是让您使用属性表达式来设置属性值,其语法与将变量作为out或ref参数传递类似 大致如下: public static foo(()=>Object.property, value); 属性将被指定为value的值 我使用以下代码获取属性的owining对象: public static object GetOwningObject<T>(this Expression<Func<T>> @this) {

我正在编写一段代码,它的最终目的是让您使用属性表达式来设置属性值,其语法与将变量作为out或ref参数传递类似

大致如下:

public static foo(()=>Object.property, value);
属性将被指定为value的值

我使用以下代码获取属性的owining对象:

public static object GetOwningObject<T>(this Expression<Func<T>> @this)
    {
        var memberExpression = @this.Body as MemberExpression;
        if (memberExpression != null)
        {
            var fieldExpression = memberExpression.Expression as MemberExpression;
            if (fieldExpression != null)
            {
                var constExpression = fieldExpression.Expression as ConstantExpression;
                var field = fieldExpression.Member as FieldInfo;
                if (constExpression != null) if (field != null) return field.GetValue(constExpression.Value);
            }
        }
        return null;
    }
public静态对象GetOwningObject(此表达式@this)
{
var memberExpression=@this.Body作为memberExpression;
if(memberExpression!=null)
{
var fieldExpression=memberExpression.Expression作为memberExpression;
if(fieldExpression!=null)
{
var constExpression=fieldExpression.Expression为常量表达式;
var field=fieldExpression.Member作为FieldInfo;
if(constExpression!=null)if(field!=null)返回field.GetValue(constExpression.Value);
}
}
返回null;
}
因此,当在像()=>Object.property这样的属性表达式上使用时,会返回“Object”的实例。我对使用属性表达式有点陌生,似乎有很多不同的方法来完成事情,但我想扩展到目前为止的内容,以便给定一个表达式,例如()=>Foo.Bar.Baz,它将给出Bar,而不是Foo。我始终希望表达式中最后一个包含对象


有什么想法吗?提前感谢。

您需要做的是通过属性链遍历到最外部的对象。 下面的示例是不言自明的,并表明扩展方法适用于链接字段和属性:

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

class Bar
{
    public string Baz { get; set; }
}

class FooWithField
{
    public BarWithField BarField;
}

class BarWithField
{
    public string BazField;
}

public static class LambdaExtensions
{
    public static object GetRootObject<T>(this Expression<Func<T>> expression)
    {
        var propertyAccessExpression = expression.Body as MemberExpression;
        if (propertyAccessExpression == null)
            return null;

        //go up through property/field chain
        while (propertyAccessExpression.Expression is MemberExpression)
            propertyAccessExpression = (MemberExpression)propertyAccessExpression.Expression;

        //the last expression suppose to be a constant expression referring to captured variable ...
        var rootObjectConstantExpression = propertyAccessExpression.Expression as ConstantExpression;
        if (rootObjectConstantExpression == null)
            return null;

        //... which is stored in a field of generated class that holds all captured variables.
        var fieldInfo = propertyAccessExpression.Member as FieldInfo;
        if (fieldInfo != null)
            return fieldInfo.GetValue(rootObjectConstantExpression.Value);

        return null;
    }
}

[TestFixture]
public class Program
{
    [Test]
    public void Should_find_root_element_by_property_chain()
    {
        var foo = new Foo { Bar = new Bar { Baz = "text" } };
        Expression<Func<string>> expression = () => foo.Bar.Baz;
        Assert.That(expression.GetRootObject(), Is.SameAs(foo));
    }

    [Test]
    public void Should_find_root_element_by_field_chain()
    {
        var foo = new FooWithField { BarField = new BarWithField { BazField = "text" } };
        Expression<Func<string>> expression = () => foo.BarField.BazField;
        Assert.That(expression.GetRootObject(), Is.SameAs(foo));
    }
}
class-Foo
{
公共条{get;set;}
}
分类栏
{
公共字符串Baz{get;set;}
}
类FooWithField
{
公共酒吧;
}
BarWithField类
{
公共字符串字段;
}
公共静态类LambdaExtensions
{
公共静态对象GetRootObject(此表达式)
{
var propertyAccessExpression=expression.Body作为MemberExpression;
if(propertyAccessExpression==null)
返回null;
//通过物业/场地链向上
while(propertyAccessExpression.Expression是MemberExpression)
propertyAccessExpression=(MemberExpression)propertyAccessExpression.Expression;
//最后一个表达式假设是引用捕获变量的常量表达式。。。
var rootObjectConstantExpression=propertyAccessExpression.Expression为ConstantExpression;
if(rootObjectConstantExpression==null)
返回null;
//…存储在包含所有捕获变量的已生成类的字段中。
var fieldInfo=propertyAccessExpression.Member作为fieldInfo;
如果(fieldInfo!=null)
返回fieldInfo.GetValue(rootObjectConstantExpression.Value);
返回null;
}
}
[测试夹具]
公共课程
{
[测试]
public void应通过属性链()查找根元素
{
var foo=newfoo{Bar=newbar{Baz=“text”};
表达式=()=>foo.Bar.Baz;
Assert.That(expression.GetRootObject(),Is.SameAs(foo));
}
[测试]
public void应通过字段链()查找根元素
{
var foo=new FooWithField{BarField=new BarWithField{BazField=“text”};
表达式=()=>foo.BarField.BazField;
Assert.That(expression.GetRootObject(),Is.SameAs(foo));
}
}

如果您的项目是MVC 5项目,并且您有对程序集
System.Web.MVC
的引用,则可以使用以下内容:

不久前,我编写了一个扩展方法来轻松创建一个multiselect下拉列表(基于bootstrap 4),它看起来像这样:

public static MvcHtmlString MultiSelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
/*The challenge I faced here was that the expression you passed could very well be nested, so in order overcome this, I decompiled the dll to see how MVC does it, and I found this piece of code.*/

 string expressionText = System.Web.Mvc.ExpressionHelper.GetExpressionText((LambdaExpression)expression);
 System.Web.Mvc.ModelMetadata metadata = System.Web.Mvc.ModelMetadata.FromStringExpression(expressionText, htmlHelper.ViewData);

}
public static MvcHtmlString MultiSelectFor(此HtmlHelper HtmlHelper,表达式)
{
/*我在这里面临的挑战是,您传递的表达式很可能是嵌套的,因此为了克服这一点,我对dll进行了反编译,以了解MVC是如何做到这一点的,我发现了这段代码*/
string expressionText=System.Web.Mvc.ExpressionHelper.GetExpressionText((LambdaExpression)表达式);
System.Web.Mvc.ModelMetadata metadata=System.Web.Mvc.ModelMetadata.FromStringExpression(expressionText,htmlHelper.ViewData);
}

metadata
对象有一个名为
PropertyName
的属性和另一个名为
Container
的属性,该属性是容器对象实例的引用。

很抱歉,这么多年前我错过了这个属性!我会尝试一下,但那个代码早就不存在了,但对我来说似乎很好。