对集合的隐式转换

Set*_*thO 9 c# linq implicit-conversion

本周我遇到了关于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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是当我有一个Foo对象列表,并希望使用我的隐式运算符将它们转换为FooVO对象列表.

List<Foo> foos = GetListOfBusinessFoos(); // Get business objects to convert
Run Code Online (Sandbox Code Playgroud)

我试过了

List<FooVO> fooVOs = foos; // ERROR
Run Code Online (Sandbox Code Playgroud)

List<FooVO> fooVOs = (List<FooVO>) foos; // ERROR
Run Code Online (Sandbox Code Playgroud)

乃至

List<FooVO> fooVOs = foos.Select( x => x ); // ERROR
Run Code Online (Sandbox Code Playgroud)

我知道我可以在循环中执行此操作,但我希望能够直接(LINQ?)方式一次性转换对象.有任何想法吗?

先感谢您.

编辑 修复了示例中的拼写错误

Eri*_*ert 22

几乎每天都会问这样一个问题.你不能这样做,因为这样做会违反类型安全:

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.
Run Code Online (Sandbox Code Playgroud)

在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

从底部开始.

  • OP从未说过 FooVO 是 Foo 的子类,因此 a.Add(new Tiger()) 无法编译。OP询问了两个需要相互转换的独立类。这种情况在MVVM编程中经常出现。我从数据库中获取 List&lt;Customer&gt; 并需要转换为 List&lt;CustomerViewModel&gt; 以将数据绑定到视图。 (2认同)
  • // 没有; 我们刚刚在长颈鹿列表中添加了一只老虎。不,你在动物列表中添加了一只老虎,这很好。我不明白为什么这会破坏类型安全。 (2认同)
  • @LHolleman:引用类型的值是**引用**.现在清楚了吗? (2认同)

sma*_*man 19

您的示例不起作用的原因是因为您尝试将IEnumerable<FooVO>a 分配给a List<FooVO>.以下应该有效.

 List<FooVO> fooVos = foos.Select<Foo,FooVO>(x => x).ToList();
Run Code Online (Sandbox Code Playgroud)


Mik*_*ler 10

List<FooVO> d = new List<FooVO>(foos.Select(x => (FooVO)x)); 
Run Code Online (Sandbox Code Playgroud)

适合我.


Akh*_*hil 7

使用ConvertAll方法传入static implicit operator FooVO( Foo foo )作为参数

List<FooVO> fooVOs = foos.ConvertAll<FooVO>(FooVO.FooVO);
Run Code Online (Sandbox Code Playgroud)

  • 我的上述示例代码和您的建议出现编译器错误。但是,如果我用 (x =&gt; x) 替换 (FooVO.FooVO) 它将起作用。我之前没有使用 ConvertAll&lt;T&gt;() - 谢谢你的建议。 (3认同)