简体   繁体   English

在linq或lambda表达式中转换匿名对象的类型

[英]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. 我遇到以下情况,我有一个返回List<object ,因为该对象可以是2个不同的类型Class1Class2 ,但从不混合。 I use this List for a lot of things, but at some point I need a list with names of the objects: List<string> . 我将这个List用于很多事情,但是有时需要一个列出对象名称的List<string>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. 我知道如何在for循环中执行此操作,但是我想知道是否有一个很好的linq / lambda技巧。 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. 我也知道这可以视为危险代码,但是在我的情况下,返回对象的类型由useFullProces布尔值定义,因此可以正常工作。

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: 可以Select使用强制类型转换,但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 ). 如果您知道将只有Class1Class2作为类型,并且每个类型在不同的if-else branch上都可用, if-else branch可以利用DLR (动态语言运行时)。

Let's say you have the 2 classes you mentioned above. 假设您有上面提到的2个classes

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. 因此,在if分支上,假设您有一个由Class2类型的对象形成的列表,在else分支上,您具有了一个具有Class1对象的列表。

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. 此时,您具有由Class1Class2对象形成的动态对象列表,但从未混合在一起。 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 ). 您不会得到RuntimeBindingException异常,因为列表中有相同类型的对象,并且从列表中请求该项目中不存在的属性时,也不会获得RuntimeBindingException ,因为您知道要问什么(正如您在问题中所说的)。

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. 注意 :如果您的列表中混有Class1Class2对象,则在请求不存在的字段时会出现运行时异常。

Not another note : Note I made above is also available for cast. 没有其他注释 :我在上面所做的注释也可用于投射。 You'll get System.InvalidCastException exception. 您将获得System.InvalidCastException异常。

You won't have intellisense because your type is evaluated by DLR at execution time and not at the compile time. 您不会有intellisense因为您的类型是在执行时而不是在编译时由DLR评估的。 Also you don't need to make other casts, boxing or unboxings in your code. 另外,您无需在代码中进行其他强制转换,装箱或拆箱。

PS: DLR is available from C# 4.0 PS:C#4.0中提供了DLR

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM