0

我做下一件事......我将一些控件的字段传递给一些函数,例如:

class ScenarioSelector
{
    public ScenarioSelector()
    {
        SubjectInfo.SetStr(lbl_labs_header.Text);
    }
}

class SubjectInfo
{
    public static void SetStr(object obj)
    {
        string name = obj.GetType().Name;
        string full_name = obj.GetType().FullName;
        Type t = obj.GetType();

        //FieldInfo fi = FieldInfo.GetFieldFromHandle(/*I don't have any handle here*/);

        //Somehow understand that passed object is... "ScenarioSelector.lbl_labs_header.Text" and set it's value depending from it.
    }
}

函数 SetStr 应该理解传递对象的字段名称,并根据它的名称设置它的值。我尝试了一些东西,但无法得到我需要的东西,我只得到 System.String 作为名称。 在此处输入图像描述

这背后的整个想法是界面翻译。我想在文件中存储类似: [ScenarioSelector.lbl_labs_header.Text][TEXT_ON_THIS_LABEL] 并通过调用函数SetStr轻松设置它

也许您对如何以另一种方式或修复我的方式有一些想法?

PS基于Medinoc示例,我这样做了:

static void Test3<T>(Expression<Func<T>> exp)
{
    Expression body = exp.Body;
    List<string> memberNames = new List<string>();
    MemberInfo previousMember = null;

    while(body.NodeType == ExpressionType.MemberAccess)
    {
        MemberExpression memberBody = (MemberExpression)body;
        string memberName = memberBody.Member.Name;

        if (previousMember == null) //this is first one
        {
            switch (memberBody.Member.MemberType)
            {
                case MemberTypes.Field:
                    ((FieldInfo)memberBody.Member).SetValue(/*How to get the object instance?*/, "some_val");
                    break;

                case MemberTypes.Property:
                    break;

                default:
                    break;
            }
        }

        if (memberBody.Expression.NodeType == ExpressionType.Constant && previousMember != null) //If it's the 'last' member, replace with type
            memberName = previousMember.DeclaringType.Name;

        memberNames.Add(memberName);
        previousMember = memberBody.Member;
        body = memberBody.Expression;
    }

    memberNames.Reverse();
    Console.WriteLine("Member: {0}", string.Join(".", memberNames));
}

但仍然不知道如何获取对象实例来设置所需的值。

4

2 回答 2

2

在没有 lambda 表达式经验的情况下,我设法构建了一个示例:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace TestsA
{
    class TestLambdaExpression
    {
        class Inner { public int tata; }

        string toto;
        Inner tutu;

        static void Test3<T>(Expression<Func<T>> exp)
        {
            Expression body = exp.Body;
            List<string> memberNames = new List<string>();
            while(body.NodeType == ExpressionType.MemberAccess)
            {
                MemberExpression memberBody = (MemberExpression)body;
                memberNames.Add(memberBody.Member.Name);
                body = memberBody.Expression;
            }
            memberNames.Reverse();
            Console.WriteLine("Member: {0}", string.Join(".", memberNames));

        }

        public static void Test()
        {
            TestLambdaExpression obj = new TestLambdaExpression();
            obj.toto = "Hello world!";
            obj.tutu = new Inner();
            obj.tutu.tata = 42;

            Test3(() => obj.toto);
            Test3(() => obj.tutu.tata);
        }
    }
}

调用TestLambdaExpression.Test应该输出:

Member: obj.toto
Member: obj.tutu.tata

编辑:

对于您的特殊输出,可以添加一个测试:

        static void Test3<T>(Expression<Func<T>> exp)
        {
            Expression body = exp.Body;
            List<string> memberNames = new List<string>();
            MemberInfo previousMember = null;
            while(body.NodeType == ExpressionType.MemberAccess)
            {
                MemberExpression memberBody = (MemberExpression)body;
                string memberName = memberBody.Member.Name;
                //If it's the 'last' member, replace with type
                if(memberBody.Expression.NodeType == ExpressionType.Constant && previousMember != null)
                    memberName = previousMember.DeclaringType.name;
                memberNames.Add(memberName);
                previousMember = memberBody.Member;
                body = memberBody.Expression;
            }
            memberNames.Reverse();
            Console.WriteLine("Member: {0}", string.Join(".", memberNames));

        }

Edit2:为了修改变量,我设法做到了:

private static void TestAssign<T>(Expression<Func<T>> exp, T toAssign)
{
    Expression assExp = Expression.Assign(exp.Body, Expression.Constant(toAssign));
    Expression<Func<T>> newExp = exp.Update(assExp, null);
    newExp.Compile().Invoke();
}

它可能不是最快也不是最有效的方法,但它应该是最通用的。

于 2013-10-16T09:50:49.527 回答
1

我创建了一个表单并放置了一个按钮。

当您单击按钮时,您会将其文本字段更改为文本字段的实际完整类型名称 - 例如。“Stackoverflow.Form1.button1.Text”

namespace StackOverflow
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        SubjectInfo.SetStr(button1,() => button1,()=> button1.Text);
    }
}

class SubjectInfo
{
    public static void SetStr<T,U>(object obj,Expression<Func<T>> objLambda,     Expression<Func<U>> fieldLambda)
    {
        // get the name of the field
        string fieldName = ((MemberExpression) fieldLambda.Body).Member.Name;

        // get the full name of the whole object and field as it is typed in the source code
        string full_name_in_source = ((MemberExpression)objLambda.Body).Member.DeclaringType + "." + ((MemberExpression)objLambda.Body).Member.Name + "." + fieldName;

        obj.GetType().GetProperty(fieldName).SetValue(obj,full_name_in_source);
    }
}

}

于 2013-10-16T09:57:09.690 回答