0

Sounds a little complex but here is what I am trying to do:

I am filtering certain properties of MyObject in List<MyObject> into a new LINQ object as:

 var filteredMyObjects = from r in myObjects select new { r.ComponentName, r.Group, r.Key };

The problem is now that Properties ComponentName, Group and Key should come as an input (for example List<string> of property names). This is used in my logic for exporting data into excel.

I have been trying to combine it with this idea:

typeof(MyObject).GetProperty(property).GetValue(objectInstance) as string

But cannot wrap my head around how to implement it.

EDIT:

See example of what I need to achieve:

List<string> userDefinedPropeties = new List<string> {Property1, Property2, Property3 ... }

var filteredMyObjects = from r in myObjects select new { r.Property1, r.Property2, r.Property3 ... };

Ideal answer would look like this, except this solution does not work in my case: Linq access property by variable

Community
  • 1
  • 1
eYe
  • 1,695
  • 2
  • 29
  • 54
  • 1
    I don't really understand what you want to do. Do you want to access the properties of your selected anonymous objects? In that case, why don't you create a new class, a kind of DTO I guess, that simply allows you to select new MyDtoObject { ... }? – sara Jul 10 '15 at 12:54
  • Simple. I want to pass which properties to use inside my filteredMyObjects var. – eYe Jul 10 '15 at 12:55
  • Why don't you provide a ListBox for the user to select from the available properties? Reflection is always error-prone. – Tim Schmelter Jul 10 '15 at 12:58
  • Skip the mapping of MyObject to an anonymous class. Makes no sense in this context. For the Excel file you can just write the required properties of MyObject. – Kevin Jul 10 '15 at 12:59
  • Good idea Tim but, unfortunately, I have constraints in my UI design – eYe Jul 10 '15 at 12:59
  • @eYe: what kind of _constraint_, that you must use a GUI that is likely to produce unexpected results or errors and is cumbersome? ;-) – Tim Schmelter Jul 10 '15 at 13:02
  • That this functionality cannot be brought out to front like that. Hard to explain but I am just a slave following orders here :) – eYe Jul 10 '15 at 13:03
  • @eYe you need to try to explain your problem better, I think you want to populate data from a list rather than from an object directly but I'm not sure if that is what you want – konkked Jul 10 '15 at 13:09
  • I want to populate FILTERED data from a list of objects. However the filtering options represented by property combinations are user defined. – eYe Jul 10 '15 at 13:11
  • I've updated question with an example, sorry if the question is a little confusing – eYe Jul 10 '15 at 13:14

2 Answers2

1

You can't use an anonymous object for this, your best bet is to use an expando object

//List<string> userDefinedPropeties is a parameter
List<dynamic> filteredMyObjects = new List<dynamic>();
foreach (var i in filteredMyObjects)
{

    dynamic adding = new ExpandoObject();
    foreach (var prop in userDefinedPropeties) 
    {
        adding[prop] = i.GetType().GetProperty(prop).GetValue(i);
    }

    filteredMyObjects.Add(adding);

}

// all of the elements of the filtered list can be accessed by using 
// item.`PropertyName`

Also a better way to phrase your question would be to say that you want to pass an object that only contains the properties that the user requested, not sure why the UI wouldn't be able to handle more properties than requested, but you have explained you don't have control over the design

msmolcic
  • 6,407
  • 8
  • 32
  • 56
konkked
  • 3,161
  • 14
  • 19
  • 1
    He was probably trying to escape explicit looping which slows things down a lot when implementing exports. – sonne Jul 10 '15 at 13:20
  • @sonne OP is using linq statement to iterate, just as expensive as a loop just evaluated lazily – konkked Jul 10 '15 at 13:30
  • @konkked I've tried this approach and export time was 52s for ~4000 records. When I used the query method provided within ClosedXML docs, the time has gone down to ~500ms. So unfortunately this wont work. – eYe Jul 10 '15 at 13:53
  • @eYe how are you getting this enumerable? If the Linq expression is being translated into a direct action (i.e. prepared sql stmt ) you are not going to get the same performance if you need to do reflection – konkked Jul 10 '15 at 20:40
0

You could fake dynamic properties using Dictionary:

public class CustomObject
{
    Dictionary<string, object> _properties = new Dictionary<string, object>();

    public CustomObject(dynamic parentObject, List<string> properties)
    {
        foreach (string propertyName in properties)
            _properties[propertyName] = parentObject.GetType().GetProperty(propertyName).GetValue(parentObject, null);
    }

    public object this[string name]
    {
        get
        {
            if (_properties.ContainsKey(name))
            {
                return _properties[name];
            }
            return null;
        }
        set
        {
            _properties[name] = value;
        }
    }
}

Use example:

var myObjects = new List<MyObject>()
{
    new MyObject(1, "Component1", 1, 1),
    new MyObject(2, "Component2", 2, 2),
    new MyObject(3, "Component3", 3, 3),
    new MyObject(4, "Component4", 4, 4),
    new MyObject(5, "Component5", 5, 5),
    new MyObject(6, "Component6", 6, 6),
    new MyObject(7, "Component7", 7, 7),
    new MyObject(8, "Component8", 8, 8),
};

var properties = new List<string>()
{
    "ComponentName", "Group", "Key"
};

List<CustomObject> myCustomObjects = new List<CustomObject>();
foreach (MyObject myObject in myObjects)
    myCustomObjects.Add(new CustomObject(myObject, properties));
msmolcic
  • 6,407
  • 8
  • 32
  • 56