1

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;
}
user3339411
  • 887
  • 1
  • 6
  • 10

2 Answers2

4

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#?

Community
  • 1
  • 1
Colin
  • 4,025
  • 21
  • 40
  • Sure, this would be a better way. But Lets say that i have no control over the object. – user3339411 Apr 21 '16 at 23:49
  • Do you know the person who has control of the object? Can you push back? Sometimes the proper approach to good code transcends the code itself and involves a bit of back-and-forth with other developers who can benefit from code reviews. – Colin Apr 22 '16 at 03:33
  • I'm not looking for the better way to do this. I'm looking for how to do it this way. Is there any way I can achieve what I'm looking for? In JS, for example, it's rather easy – user3339411 Apr 22 '16 at 03:35
  • In .NET it's relatively easy, too (use "dynamic", "ExpandoObject" or Newtonsoft.JSON), but I'd still advise pushing back against the design if possible. See the tweaked answer for how it would work, though. – Colin Apr 22 '16 at 04:34
  • So my comment to Nitin. This gives a key/value object, rather than an object with properties, – user3339411 Apr 22 '16 at 05:10
  • You can reference it like a property (but it belongs in a dictionary anyway, which is easier to iterate through later), so what's the problem? – Colin Apr 22 '16 at 05:54
  • You can also use System.Reflection.Emit similar to this: http://stackoverflow.com/questions/3862226/dynamically-create-a-class-in-c-sharp, but, again, why put yourself through all this trouble when much simpler alternatives exist? – Colin Apr 22 '16 at 06:05
0

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
Nitin
  • 18,344
  • 2
  • 36
  • 53
  • This would result in a KeyValuePair list where each item on that list is { Key: PropertyNameYear1, Value: Val }. I'm trying to get a list of { PropertNameYear1: Val } – user3339411 Apr 21 '16 at 23:54