简体   繁体   中英

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.

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM