views:

682

answers:

10

I'm not quite sure what I'm attempting to do is called, so I'm struggling to find any clues from google.

I have a couple of methods with the same logic in them, the only thing that differs is the property they are using on an object.

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

Instead of the three separate methods in Foo I want one, with a signature that looks more like

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

Is this possible?

+6  A: 

I misread the question the first time, my bad.

You can do this with Reflection:

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

Then, you call it like this:

Method(bar,"A");

Just noticed that in your example, the 3 variables in Bar are public instance variables. I'm assuming that you just did this for your sample, but if this is in fact the case in your real class, use Rex M's approach.

BFree
While this is possible it can cause runtime errors because the compiler has no way to check if the passed property does exist. I would think about changing the design.
VVS
A: 

You can achieve this using reflection. It will have some performance impact

Sergio
A: 

you can use the PropertyInfo class to retrieve the desired property via reflection: http://articles.techrepublic.com.com/5100-10878_11-6099345.html

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

Try using reflection. Here's some simple code to achieve the effect.

using System.Reflection;    

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

Now, you can call X by first getting the FieldInfo for one of the fields on Bar.

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

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

Use FieldInfo

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

field.SetValue(..) to set the value.

AB Kolan
+6  A: 
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;
}
That's what I was thinking but was too slow in posting :)
VVS
@Luke I was assuming the example was contrived and in practice he needs something in addition to what is shown.@unknown I was typing this up as well when I saw the new answer come through, but didn't refresh to what it was.
Mark
Why not just have a "public int X(int fieldValue)" method instead, and pass the property value directly? eg, "int y = new Foo().X(bar.A)". Your example, passing a Bar object and a Func to select the field does exactly the same thing in a roundabout way.
LukeH
@Mark, Regardless of the complexity of the OP's real code, the field selector Func is only ever going to return the value of the property, so why not just pass that value directly?
LukeH
@Luke I see your point. I could see where the method might manipulate "bar" and then need the value. The anonymous delegate would delay the execution until you want it, but that's all speculation. With the example provided, yes, passing an int would be best.
Mark
A: 

you could use an extension method.. for the example you posted.. but i guess that your example is just a simplified version of some more complex code.

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

Why not use an enumeration and pass it into the function to determine which to use? It seems reflection is kinda going west around the world to take a step to the right...

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

Then your call would be

 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);
Greg
+2  A: 

I would consider using an anonymous delegate to get your value instead.

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

Then call it like:

var x = X(mybar, x=>x.A);
Mark