user3339411
user3339411

Reputation: 917

Create properties dynamically

So I have an object with lots of properties, PropertyNameYear1, PropertyNameYear2, PropertyNameYear3...for 20 years. these properties could potentially grow with time, so in the future I might have to add PropertyNameYear21 and so on.

I'm trying to get these properties, both their name and value, without specifying each and every one, since theoretically i can have tens of them. I can do it using LINQ and Object Initializer, but then I have to specify each property twice:

new {
    PropertyNameYear1 = f => f.PropertyNameYear1,
    PropertyNameYear2 = f => f.PropertyNameYear2,
    ...
};

How can I, using LINQ (and Refelction?), get all these properties (and only these, assuming there are other properties named differently than PropertyNameYearX) into a new/another object and return that object?

This is a pseudo-code of what I'm looking for:

public ReturnType GetSomeObjectWithSpecificProperties(int ID){
    var list = SomeObjectRepository.Where(f => f.ID == ID);
    var props = list.GetType().GetProperties().ToList();
    var SomePropObjectList = props.Where(f => f.Name.Contains("PropertyNameYear")).ToList();

    var listToReturn = SomePropObjectList.Select(f => new {
        f.Name = f.GetValue(list)
    }).ToList();

    return listToReturn;
}

Upvotes: 1

Views: 133

Answers (2)

Colin
Colin

Reputation: 4135

I want to pipe in and say you should rethink your approach.

Instead of having:

public class NotGood
{
    public int PropertyNameYear1{ get; set; }
    //repeat 20 times...
    public int PropertyNameYear21{ get; set; }
}

...consider:

public class Better
{
    public List<int> PropertyNameYears{ get; } = new List<int>();
}

It's one line of code and it will scale much better. Plus, you eliminate all the clumsy, reflection-based parsing.

EDIT: As I mentioned in the comments, sometimes the proper approach to clean code is discussing bad code with the author vs. adapting your code to fit the problem they caused, but if there's no way around it, here's an approach that requires four lines of code:

var obj = new
{
    SomeNormalProp = "foo",
    ThisIsSilly1 = 1,
    ThisIsSilly2 = 2,
    ThisIsSilly3 = 3,
    ThisIsSilly4 = 4
};

dynamic barfObj = new ExpandoObject();
foreach (var prop in obj.GetType().GetProperties())
    if (prop.Name.StartsWith("ThisIsSilly"))
        //add property dynamically
        ((IDictionary<string, object>)barfObj).Add(prop.Name, prop.GetValue(obj));

//now barfObj is exactly what you want.
var sampleVal = barfObj.ThisIsSilly1;
var json = JsonConvert.SerializeObject(barfObj);

Or if you're a real masochist, you have Reflection.Emit: How to dynamically create a class in C#?

Upvotes: 4

Nitin Purohit
Nitin Purohit

Reputation: 18580

You can make use of ExpandoObject to dynamically add Properties from your source class object. Assuming the source class is ClassWithMayProperties:

    public object GetObject(ClassWithManyPropererties obj)
    {
        var props = obj.GetType().GetProperties().Where(p => p.Name.Contains("PropertyNameYear")).ToList();

        dynamic returnObject = new ExpandoObject() as IDictionary<string, Object>;

        foreach (var property in props)
        {
            returnObject.Add(property.Name, property.GetValue(obj));
        }

        return returnObject;
    }

Then you can directly get the value of property you want or cast the ExpandoObject in IDictionary and check for the property name as key.

        var dynObject = GetObject(obj);
        var d  = dynObject.PropertyNameYear1

Upvotes: 0

Related Questions