2009-05-27 4 views
4

Я не совсем уверен, что я пытаюсь это сделать, поэтому я изо всех сил пытаюсь найти какие-либо подсказки из Google.Pass FieldName как параметр

У меня есть несколько методов с одинаковой логикой в ​​них, единственное, что отличается, - это свойство, которое они используют на объекте.

class Foo 
{ 
    public int A(Bar bar) 
    { 
     return bar.A * 2; 
    } 

    public int B(Bar bar) 
    { 
     return bar.B * 2; 
    } 

    public int C(Bar bar) 
    { 
     return bar.C * 2; 
    } 
} 

class Bar 
{ 
    public int A; 
    public int B; 
    public int C; 
} 

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

public int X(Bar bar, ??? x) 
{ 
    return bar.x * 2; 
} 

Возможно ли это?

+1

Почему вы должны разделить на вызов в объект и поле, а не просто передать bar.X методу? Что мне здесь не хватает? –

+1

Это просто пример игрушки – Kirschstein

ответ

8
internal class Program { 
    private static void Main(string[] args) { 
     var bar = new Bar {A = 1, B = 2, C = 3}; 
     Console.WriteLine(new Foo().X(bar, it => it.A)); 
     Console.WriteLine(new Foo().X(bar, it => it.B)); 

     // or introduce a "constant" somewhere 
     Func<Bar, int> cFieldSelector = it => it.C; 
     Console.WriteLine(new Foo().X(bar, cFieldSelector)); 
    } 
} 

internal class Foo { 
    // Instead of using a field by name, give it a method to select field you want. 
    public int X(Bar bar, Func<Bar, int> fieldSelector) { 
     return fieldSelector(bar) * 2; 
    } 

    public int A(Bar bar) { 
     return bar.A * 2; 
    } 

    public int B(Bar bar) { 
     return bar.B * 2; 
    } 

    public int C(Bar bar) { 
     return bar.C * 2; 
    } 
} 

internal class Bar { 
    public int A; 
    public int B; 
    public int C; 
} 
+0

Вот что я думал, но был слишком медленным в публикации :) – VVS

+0

@ Luke Я предполагал, что пример был изобретен, и на практике ему нужно что-то в дополнение к тому, что показано. @unknown Я тоже набирал это, когда увидел новый ответ, но не обновился до того, что было. – Mark

+0

Почему бы просто не использовать метод public public int X (int fieldValue) и передать значение свойства напрямую? например, «int y = new Foo(). X (bar.A)». Ваш пример, передавая объект Bar и Func для выбора поля, делает то же самое в обходном пути. – LukeH

13

Я неправильно понял вопрос в первый раз, мой плохой.

Вы можете сделать это с помощью отражения:

public int Method(Bar bar, string propertyName) 
{ 
    var prop = typeof(Bar).GetProperty(propertyName); 
    int value = (int)prop.GetValue(bar,null); 
    return value * 2; 
} 

Тогда вы называете это так:

Method(bar,"A"); 

Просто заметил, что в вашем примере, 3 переменные в Баре общедоступные переменные. Я предполагаю, что вы просто сделали это для своего образца, но если это действительно так в вашем реальном классе, используйте подход Rex M.

+5

Хотя это возможно, это может привести к ошибкам во время выполнения, потому что компилятор не имеет возможности проверить, существует ли переданное свойство. Я бы подумал об изменении дизайна. – VVS

0

Вы можете достичь этого, используя отражение. Она будет иметь некоторое влияние на производительность

0
public int X(Bar bar, string target) 
{ 
    object value = bar.GetType().GetField(target, BindingFlags.Public | BindingFlags.Instance).GetValue(bar); 
    return (int)value * 2; 
} 
0

Попробуйте с помощью отражения. Вот простой код для достижения эффекта.

using System.Reflection;  

public int X(Bar bar, FieldInfo x) 
{ 
    return (int)x.GetValue(bar) * 2; 
} 

Теперь вы можете вызвать X, сначала получив полевое поле для одного из полей на панели.

Bar b = new Bar(); 
b.A = 20; 
b.B = 30; 
b.C = 40; 

FieldInfo fieldA = typeof(Bar).GetField("A"); 
int result = X(b, fieldA); 
0

Применение FieldInfo

BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; 
FieldInfo field = typeof(Bar).GetField("A", flags); 

field.SetValue (..), чтобы установить значение.

0

можно использовать метод расширения .. для примера вы публикуемые .. но я думаю, что ваш пример является лишь упрощенной версией некоторого более сложного кода.

public static class IntExt 
{ 
    //use Bar.A.Double(); 
    public int Double(this int value) 
    { 
     return value * 2; 
    } 
} 
0

Почему бы не использовать перечисление и передать его в функцию, чтобы определить, какой из них использовать? Кажется, отражение своего рода на запад по всему миру, чтобы сделать шаг вправо ...

class Foo 
{ 
    public enum BarChoice { a,b,c }; 
    public int x(Bar bar, BarChoice bc) 
    { 
    switch(bc) 
    { 
     case a: 
     return bar.A * 2; 
     case b: 
     return bar.B * 2; 
     case c: 
     return bar.C * 2; 
    } 
    return int.MinValue; 
    } 
} 

Тогда ваш звонок будет

Foo f = new foo(); 
Bar b = new Bar(); 
f.x(b, Foo.BarChoice.a); 
f.x(b, Foo.BarChoice.b); 
f.x(b, Foo.BarChoice.c); 
3

Я хотел бы рассмотреть вопрос об использовании анонимного делегата получить значение вместо.

public int X(Bar bar, Func<Bar,int> getIt) 
{ 
    return getIt(bar) * 2; 
} 

Затем вызовите его, как:

var x = X(mybar, x=>x.A); 
Смежные вопросы