C#转换问题:从IEnumerable到自定义类型

时间:2010-05-25 13:22:02

标签: c# linq inheritance interface casting

我有一个名为Rows的自定义类,它实现了IEnumerable<Row>。我经常在Rows个实例上使用LINQ查询:

Rows rows = new Rows { row1, row2, row3 };
IEnumerable<Row> particularRows = rows.Where<Row>(row => condition);

我希望能够做到以下几点:

Rows rows = new Rows { row1, row2, row3 };
Rows particularRows = (Rows)rows.Where<Row>(row => condition);

但是,我得到一个“System.InvalidCastException:无法转换'WhereEnumerableIterator1 [NS.Row]'类型的对象来键入'NS.Rows'”。我的Rows构造函数有IEnumerable<Row>,所以我可以这样做:

Rows rows = new Rows { row1, row2, row3 };
Rows particularRows = new Rows(rows.Where<Row>(row => condition));

然而,这似乎很笨重,我希望能够IEnumerable<Row>成为Rows,因为Rows实施IEnumerable<Row>。有什么想法吗?

7 个答案:

答案 0 :(得分:4)

救援的延伸方法。

public static Rows ToRows(this IEnumerable<Row> source)
{
  return new Rows(source);
}

行特殊行=行。其中(...)。ToRows();


“施法”不适合这个问题。每个Rows都是IEnumerable<Row>,但不是每个IEnumerable<Row>都是Rows

答案 1 :(得分:2)

如果对象实际上是该类的实例,则只能将对象强制转换为特定的类。

在您的情况下,从LINQ调用获得的IEnumerable<Row>不是Rows实例,并且.Net运行时无法将其神奇地转换为Rows实例。< / p>

相反,您需要创建一个从Rows创建新IEnumerable<Row>实例的函数。该函数可能应该是构造函数重载或扩展方法。

顺便说一句,请注意,标准的.Net命名约定表明您的Rows类实际上应该被称为RowCollection

答案 2 :(得分:1)

虽然Rows可能会实现IEnumerable<Row>并不意味着任何IEnumerable<Row>都是Rows,所以编译器不能让你做出这样的假设。 / p>

答案 3 :(得分:1)

你必须记住,虽然你可以建立继承链(Row - &gt; IEnumerable),但没有可靠的方法来抛弃继承链。

请考虑以下事项:

List<Row> rows = new List<Row>();

// Fill the list
IEnumerable<Row> rowsAsEnumerable = (IEnumerable<Row>)rows;

Rows realRows = (Rows)rowsAsEnumerable;

由于rowsAsEnumerable永远不是Rows对象,系统如何处理强制转换?

答案是它不可能,因为即使Rows对象始终是IEnumerable,IEnumerable也不总是Rows对象。

<强>更新

由于我不喜欢做一个梦想破碎机,我会重新改变其他人所说的话。

您可以使用简单的Extension方法从示例中使事情变得更清晰:

public static Rows ToRows(this IEnumerable<Row> rowsAsEnum)
{
    return new Rows(rowsAsEnum);
}

现在您可以将通话更改为:

Rows particularRows = rows.Where<Row>(row => condition).ToRows();

答案 4 :(得分:0)

这有用吗?

Rows particularRows = (Rows)(rows.Where<Row>(row => condition).ConvertAll(r=>(Row)r));

您还可以为上面添加扩展方法包装器(这将是最干净的解决方案),因此您可以执行以下操作:

Rows particularRows = rows.Where<Row>(row => condition).ToRows();

答案 5 :(得分:0)

基本上你在这里提出的任何解决方案都将涉及环绕构造函数,它包含一个IEnumerable

我的原始答案定义了转换解决方案(但我无法编译并看到错误)。

我要做的是为IEnumerable定义一个扩展方法:

public static Rows ToRows(this IEnumerable<Row> rows)
{
  return new Rows(rows);
}

然后你可以非常干净地使用它:

public void Foo(IEnumerable<Row> rows)
{
   Rows r = rows.Where(r => condition).ToRows();
}

答案 6 :(得分:-1)

您需要在班级中定义explicit cast

public class Rows : IEnumerable<Row>
{
    public static explicit operator MyType(IEnumerable<Row> x)
    {
        return new Rows(x); // using your constructor
    }
}

这将告诉C#允许你的演员:

Rows particularRows = (Rows)rows.Where<Row>(row => condition);