1

I am working on a website that features a graphing tool, allowing the user to pick up to 3 properties to be displayed on a graph.

I have a database with structure similar to the following:

public class MyClass
{
    public decimal Field1 {get;set;}
    public decimal Field2 {get;set;}
    ...
    public decimal Field10 {get;set;}
}

I need the user to be able to select up to 3 properties, which are then returned in an object.

public class MyResult
{
    public decimal value1 {get;set;}
    public decimal value2 {get;set;}
    public decimal value3 {get;set;}
}

The website contains three dropdowns, with the user picking which of the 10 fields they want to graph as value1,2 or 3.

As a result of this, the value passed into the controller will be a string detailing the column name, however as Linq is strongly typed, the two cannot be interchanged.

How can I write a Linq command that isn't strongly typed, but instead uses the text passed in by the user as the column name?

Something like the following would have been ideal, but doesn't work.

values.Select(x => new MyResult(){ value1 = "Field1", value2 = "Field5", value3 = "Field9"});

Or am I just looking at this the completely wrong way? Is there a better way of achieving this?

Gavin Coates
  • 1,366
  • 1
  • 20
  • 44
  • You can do this by `Reflection`. – Rahul Singh Sep 24 '15 at 11:05
  • As the others have mentioned, `Reflection` is what you are looking for here. But you should know that [reflection is an expensive operation](http://stackoverflow.com/questions/25458/how-costly-is-net-reflection) and in this case looks like it might really kill your performance. – ethorn10 Sep 24 '15 at 11:27
  • I post an answer, let me know if it solves your problem. – Hossein Narimani Rad Sep 24 '15 at 11:44

2 Answers2

2

It's not LinQ, but you might consider using AutoMapper, it's very convenient in this situation.

Sample:

 Mapper.CreateMap<MyClass, MyResult>()
                .ForMember(dest => dest.Field1, opt => opt.MapFrom(src => src.Value1))
                .ForMember(dest => dest.Field2, opt => opt.MapFrom(src => src.Value2))
                .ForMember(dest => dest.Field3, opt => opt.MapFrom(src => src.Value3))

And later you can call:

MyResult result = Mapper.Map<MyClass>(class);
Kien Chu
  • 4,735
  • 1
  • 17
  • 31
1

Using Reflection you can get property values of a class, having their name. Here is the code:

public object GetPropertyOfMyClass(string propertyName, MyClass instance)
{
    System.Reflection.PropertyInfo[] properties = typeof(MyClass).GetProperties();

    return properties.Single(i => i.Name == propertyName).GetValue(instance);
}

Then use it like this:

values.Select(x => new MyResult(){ 
                   value1 =  (decimal)GetPropertyOfMyClass("Field1",x),
                   value2 =  (decimal)GetPropertyOfMyClass("Field5",x),
                   value3 =  (decimal)GetPropertyOfMyClass("Field9".x)});
Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116