本周我遇到了关于C#集合中隐式转换的问题。虽然这(使用implicit
)可能不是我们的最终方法,但我想至少完成代码以提供团队作为选项。我将问题归结为以下示例案例:
我的示例中有两个类:一个代表业务对象(Foo),另一个代表此业务项(FooVO)的客户端版本(View Object),如下所定义...
public class Foo
{
public string Id {get; set;}
public string BusinessInfo {get; set;}
}
public class FooVO
{
public string Id {get; set;}
public static implicit operator FooVO( Foo foo )
{
return new FooVO { Id = foo.Id };
}
}
我的问题是当我有一个Foo对象列表并希望使用我的隐式运算符将它们转换为FooVO对象列表时。
List<Foo> foos = GetListOfBusinessFoos(); // Get business objects to convert
我试过
List<FooVO> fooVOs = foos; // ERROR
和
List<FooVO> fooVOs = (List<FooVO>) foos; // ERROR
甚至
List<FooVO> fooVOs = foos.Select( x => x ); // ERROR
我知道我可以在循环中执行此操作,但我希望能够直接(LINQ?)方式一次性转换对象。有什么想法吗?
提前谢谢。
修改的 修复了示例中的拼写错误
答案 0 :(得分:21)
几乎每天都会问这样一个问题。你不能这样做是因为这样做违反了类型安全:
List<Giraffe> g = new List<Giraffe>();
List<Animal> a = g; // Should this be legal?
a.Add(new Tiger()); // Nope; we just added a tiger to a list of giraffes.
在C#4.0中,您可以隐式地从IEnumerable<Giraffe>
转换为IEnumerable<Animal>
,因为没有“添加”方法可以搞砸了。但是,如果元素类型的转换是用户定义的,那么你永远不能进行“协变”转换。它必须是引用或身份转换。
您需要创建第二个列表并一次复制一个列表。或者使用诸如Select和ToList之类的LINQ辅助方法为您完成这项工作。
您想要的类型系统概念的名称是“协方差”;协变关系就是你推理“长颈鹿是动物因此长颈鹿的序列是动物序列”的关系。如果这个主题让您感兴趣,那么您可以在这里阅读我们如何在C#4.0中添加协方差(和逆变):
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx
从底部开始。
答案 1 :(得分:18)
您的示例不起作用的原因是您尝试将IEnumerable<FooVO>
分配给List<FooVO>
。以下应该有效。
List<FooVO> fooVos = foos.Select<Foo,FooVO>(x => x).ToList();
答案 2 :(得分:9)
List<FooVO> d = new List<FooVO>(foos.Select(x => (FooVO)x));
适合我。
答案 3 :(得分:6)
使用转换static implicit operator FooVO( Foo foo )
作为参数的ConvertAll方法
List<FooVO> fooVOs = foos.ConvertAll<FooVO>(FooVO.FooVO);