类成员作为第一类对象

时间:2011-03-10 16:36:01

标签: c# introspection

我想知道c#中是否有能够将类的成员传递给另一个将使用此成员获取值的函数。因此,获取在运行时仅确定哪一个字段的值。像其他语言(至少我认为PHP)你可以做的事情

a.b = "something"

但也

a["b"] = "something";

编辑:由于使用了字符串,实际上不是很好的例子,抱歉

为清楚起见,我希望能够做到的一个例子:

class A
{
    int x;
    int y;
}

void somethingsomething<T>(T class, SomeMagicFieldClass f)
{
    dosomethingwith(somemethodthatgivesmethevalueoffield(class, f));
}

然后我可以这样调用这个方法:

A a = new A();
somethingsomething(a, A.x); //hypothetical notation
somethingsomething(a, A.y);

我现在有类似的地方:

somethingsomething(a, "x");
somethingsomething(a, "y");

然后我使用内省API(也尝试GetProperty)找到该字段

MemberInfo memberInfo = item.GetType().GetField(fieldName);

这样可行,但缺点是在视觉工作室中“重构”字段名时,作为字符串传递的字段不会更新,所以我想也许在c#中存在这样的东西会在更改字段时自动重构名字?

非常感谢您阅读这个无聊的问题

5 个答案:

答案 0 :(得分:4)

您的示例看起来很像LINQ键选择器,在该表单中看起来像:

A a = new A();
somethingsomething(a, p => p.x);

答案 1 :(得分:1)

你可以使用LINQ Expressions做一些很好的重构友好的东西。这是我用于此类场合的实用代码片段。它允许您获取属性的名称,类型和值(它不适用于没有修改的字段)。还有一个价值的设定者。

public static void Main(string[] args) {
    var test = new { Test1 = 42, Test2 = "123", Test3 = 3.14195 };

    somethingSomething(test, t => t.Test1);
    somethingSomething(test, t => t.Test2);
    somethingSomething(test, t => t.Test3);
}

static void somethingSomething<TObj,TProperty>(TObj obj, Expression<Func<TObj,TProperty>> expr) {
    var accessor = GetMemberAccessor(expr, obj);

    String name = accessor.Name;
    TProperty value = accessor.Value;
    String typeName = accessor.Type.Name;
    Console.WriteLine("{0} = {1} ({2})", name, value, typeName);
}

输出结果为:

Test1 = 42 (Int32)
Test2 = 123 (String)
Test3 = 3.14195 (Double)

为了使这项工作,我使用了以下辅助函数和类:

public static MemberAccessor<TReturn> GetMemberAccessor<TObj,TReturn>(Expression<Func<TObj, TReturn>> expr, TObj tar) {
    var body = expr.Body;

    MemberExpression memberExpression = null;
    if (body is UnaryExpression) {
        var ue = (UnaryExpression)body;
        memberExpression = (MemberExpression)ue.Operand;
    } else if (body is MemberExpression)
        memberExpression = (MemberExpression)body;
    else
        throw new NotImplementedException("can't get MemberExpression");

    String name = memberExpression.Member.Name;

    return new MemberAccessor<TReturn>(tar, name);
}

public class MemberAccessor<T> {
    private readonly PropertyDescriptor propertyDesc;
    private readonly Object target;

    public MemberAccessor(Object target, String propertyName) {
        this.target = target;
        this.propertyDesc = TypeDescriptor.GetProperties(target)[propertyName];
    }
    public String Name {
        get { return propertyDesc.Name; }
    }
    public Type Type {
        get { return propertyDesc.PropertyType; }
    }        
    public T Value {
        get { return (T)Convert.ChangeType(propertyDesc.GetValue(target), typeof(T)); }
        set { propertyDesc.SetValue(target, value); }
    }
}

答案 2 :(得分:0)

听起来像dynamic type可能会起作用。

答案 3 :(得分:0)

先生。 Plunkett是正确的;动态类型将完成这项工作。幸运的是,.NET 4团队包含了一个名为ExpandoObject的便捷对象,可以为您解决这个问题。

答案 4 :(得分:0)

你问过如何

  

将类的成员传递给另一个   将使用此成员的函数   得到一个值

您可以将delegates用于此

   class A
   {
       public string aField;

       public string aProperty{get{return "someval";}}

       public string aMemberFunction(){return "someval";}
   }


   void get_a_value(Func<string> func)
   {
       string theValue = func();
   }

   // use it:
   A a = new A();

   get_a_value( () => a.aField);
   get_a_value( () => a.aProperty);
   get_a_value( () => a.aMemberFunction());

当然,你不会这样做的是成员函数和你传递的对象的参数分离。