Член класса как первоклассный объект - PullRequest
0 голосов
/ 10 марта 2011

Мне было интересно, есть ли что-то в c #, чтобы можно было передать член класса другой функции, которая будет использовать этот член для получения значения.Так что получите значение поля, определяемого только тем, которое во время выполнения.Что-то похожее на другие языки (по крайней мере, на мой взгляд, PHP), что вы можете сделать

a.b = "something"

, но также

a["b"] = "something";

edit: на самом деле это не очень хороший пример, так как используется строка,извините

Для ясности пример того, что я хотел бы сделать:

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

Это работает, но недостатком является то,поля, переданные в виде строки, не будут обновляться при «рефакторинге» имен полей в Visual Studio, поэтому я подумал, может быть, есть что-то подобное в c #, которое будет автоматически реорганизовываться при изменении имен полей?

Большое спасибоза чтение этого скучного вопроса

Ответы [ 5 ]

4 голосов
/ 10 марта 2011

Ваш пример очень похож на ключевой селектор LINQ, в таком виде он будет выглядеть так:

A a = new A();
somethingsomething(a, p => p.x);
1 голос
/ 10 марта 2011

С 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); }
    }
}
0 голосов
/ 10 марта 2011

Вы спросили, как

передать член класса другой функции, которая будет использовать этот член для получения значения

Вы можете использовать delegates дляthis

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

То, что вы не получите таким образом, конечно, является разделением параметров для функции-члена и объекта, который вы передаете.

0 голосов
/ 10 марта 2011

г. Планкетт прав; динамический тип сделает работу. К счастью, команда .NET 4 включила удобный объект под названием ExpandoObject , который решает эту проблему для вас.

0 голосов
/ 10 марта 2011

Похоже, что динамический тип может сделать эту работу.

...