简体   繁体   中英

Convert type of anonymous object in linq or lambda expression

I have the following situation, I have a function which returns a List<object , because the object can be 2 different types Class1 or Class2 , but never mixed. I use this List for a lot of things, but at some point I need a list with names of the objects: List<string> .

I know how to do this in a for loop, but I would like to know if there is a neat linq/lambda trick for this. Since it simplifies the code.

// An extreme simplified version of my code
List<object> result = this.ProcesInput(input, useFullProces);
List<string> resultNames;

// The following ideas didn't work.
if (useFullProces)
{
    resultNames = result.Select(x as Class2 => x.ID.toString()).ToList();
    resultNames = result.Select(x => (Class2)x.ID.toString()).ToList();
}
else
{
    resultNames = result.Select(x as Class1 => x.name).ToList();
}

Also I know this can be considered dangerous code, but in my situation the type of the returned object is defined by the useFullProces boolean and will therefore work.

I suspect you just want:

List<string> names = useFullProcess
    ? result.Cast<Class2>().Select(x => x.ID.ToString()).ToList()
    : result.Cast<Class1>().Select(x => x.Name).ToList();

You can use a cast within your Select , but it's not as clear IMO:

List<string> names = useFullProcess
    ? result.Select(x => ((Class2) x).ID.ToString()).ToList()
    : result.Select(x => ((Class1) x).Name).ToList();

You need to cast the correct object:

resultNames = result.Select(x => ((Class2)x).ID.toString()).ToList();

or:

resultNames = result.Select(x => (x as Class2).ID.toString()).ToList();

EDIT : As I see there are already two answer which uses cast, so I am going to propose you another solution.That doesn't mean you have to implement it or not.

If you know you're going to have only Class1 and Class2 as types and each one is available on different if-else branch you can take advantage of DLR ( dynamic language runtime ).

Let's say you have the 2 classes you mentioned above.

public class Class1
{
   public string Name { get; set; }
}

public class Class2
{
   public int ID { get; set; }
}

You said you know on each branch what types you. So on if branch let's say you have a list formed by Class2 type objects and on else branch you have a list with Class1 objects.

List<dynamic> result = this.ProcesInput(input, useFullProces);
List<string> resultNames;

At this point you have a list of dynamic objects formed by Class1 or Class2 objects, but never mixed. So both cast and using dynamic should work. You won't get a cast exception because you have objects of same type in your list and also you won't get RuntimeBindingException when requesting for a property that doesn't exist on that item from the list, because you know what to ask for ( as you said in your question ).

You should be able to do something like this:

if (useFullProces)
{
    resultNames= result.Select(x=>x.ID).ToList();  
}
else
{
    resultNames = result.Select(x=>x.Name).ToList();
}

Note : If your list is mixed with Class1 and Class2 objects you'll get a runtime exception when requesting for a field that doesn't exists.

Not another note : Note I made above is also available for cast. You'll get System.InvalidCastException exception.

You won't have intellisense because your type is evaluated by DLR at execution time and not at the compile time. Also you don't need to make other casts, boxing or unboxings in your code.

PS: DLR is available from C# 4.0

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