Is there a way to get field name including class containing it and another class containing this class if field passed into function as object?

StackOverflow https://stackoverflow.com/questions/19397898

Question

I doing next thing... I pass into some function the field of some controls, like:

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.
    }
}

Function SetStr should understand the field name of passed object and set it's value depending of it's name. I tried something, but can't get what I need, I only getting System.String as name. enter image description here

Whole idea behind that is interface translation. I want to store in file something like: [ScenarioSelector.lbl_labs_header.Text][TEXT_ON_THIS_LABEL] And easy set it by calling function SetStr

Maybe you have some ideas of how to make it another way or fix my way?

P.S. Based on Medinoc example I did this:

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));
}

But still don't know how to get instance of object to set needed value.

Was it helpful?

Solution

Without prior experience of lambda expressions, I managed to construct an example:

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);
        }
    }
}

Calling TestLambdaExpression.Test should output:

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

Edit:

For your special output, a test can be added:

        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: For modifying the variable, I managed to make this:

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();
}

It's probably not the fastest nor the most efficient way to do it, but it should be the most versatile.

OTHER TIPS

I created a Form and placed a button.

When you click the button you will change it's Text field to the actual full typed name of the Text field - eg. "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);
    }
}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top