Justin
Justin

Reputation: 6549

Generic function that takes properties as parameters

I want to write a generic function that takes an object and a series of properties of this object. Inside the function I would like to select a new anonymous object that is simply just those properties of the passed in object.

I want to do something like this:

public class SimpleClass
{
    public DateTime ADate {get; set;}
    public string StringHere {get; set;}
    public int ANumber {get; set;}
}

var testObj = new SimpleClass();
// set values here on testObj properties
DoStuffHere(testObj, StringHere, ANumber);

I could pass in the properties as strings and then use reflection to get the properties from the passed in object, but I wanted to know if there was some way I could pass in the properties themselves so I could have intellisense and compile time checking to prevent bad property names. I would like my getNewClass function to take any type of object, and such, be generic.

Edit: I am not returning a new anonymous type. I think my function name was making it sound that way. I am going to be selecting a new anonymous type internally from a list of that specified testObj and generating a PDF from those properties.

Upvotes: 2

Views: 1689

Answers (3)

Marc Gravell
Marc Gravell

Reputation: 1062590

Defining an anonymous type is actually very complicated, and trying to do it just with the names is somewhat challenging. Essentially what you want already exists, but in regular C# - so for a single object:

var obj = new { testObj.StringHere, testObj.ANumber };

Or for multiple objects:

var projection = from obj in sequence
                 select new { obj.StringHere, obj.ANumber };

That's about as succinct as you'll get. You could add a generic method that took a Func<,> of some kind, but it wouldn't be any cleaner than the above.

It isn't useful to have:

var obj = SomeMagicMethod(obj, "StringHere", "ANumber");

because SomeMagicMethod could only usefully return object - our obj variable would be largely unusable.


If you don't need to return the object from the method, then you could use either of:

SomeMagicMethod<T>(T value) {
   ...
}
...
SomeMagicMethod(new {testObj.StringHere, testObj.ANumber });

or:

SomeMagicMethod<TFrom, TTo>(TFrom value, Func<TFrom, TTo> selector)
{
    TTo actualVal = selector(value);
    ...
}
...
SomeMagicMethod(testObj, x => new {x.StringHere, x.ANumber });

Personally, I think the first is easier - the func in the second is overkill.

You could also just use reflection...

SomeMagicMethod(object obj, params string[] names)
{
    foreach(var name in names) {
       object val = obj.GetType().GetProperty(name).GetValue(obj);
       // ...
    }
}
//...
SomeMagicMethod(testObj, "StringHere", "ANumber");

Upvotes: 4

Kenneth
Kenneth

Reputation: 28737

You can use Linq expressions for that.

(note: it's possible you need to modify a few things in the snippet below, this is of the top of my hat):

public void getNewClass(Object testObj, params MemberExpression Fields[])
{
    foreach(MemberExpression field in Fields)
    {
        // Get the name
        var name = field.Member.Name;

        // get the value
        var member= Expression.Convert(field, typeof(object));
        var lambda= Expression.Lambda<Func<object>>(member);
        var fnc= lambda.Compile();

        var value = fnc();
    }
}

This snippet show how to get the name of the property and the value. It can be called like this:

getClass(someObj, obj => obj.SomeProperty, obj.SomeOtherProperty);

Upvotes: 0

Stephane Delcroix
Stephane Delcroix

Reputation: 16222

you can pass them as lambda:

GetNewClass (testObj, ()=>StringHere, ()=> ANumber);

and have a signature for GetNewClass like

void GetNewClass (object, Expression<Func<object>> expr0, Expression<Func<object>> expr1);

You can then get the property quite easily.

Upvotes: 0

Related Questions