如何实现隐式强制转换

本文关键字:转换 何实现 实现 | 更新日期: 2023-09-27 18:11:17

我看到一些属性允许为casted implicitly。像DataTable.Rows一样,可以在DataRowDateRowView中浇注。

void DemoFunc()
{
    DataTable dtTable = new DataTable();
    foreach (DataRow row in dtTable.Rows)
    {

    }
    foreach (DataRowView row in dtTable.Rows)
    {
    }
}

我可以在自己的代码中使用这种行为。有人知道一个简单的例子来理解它是如何工作的吗?

编辑:

我的目标是什么?我想知道是否有可能设计这样的代码:

Void DemoFunc2()
{
MyObject myObjec = new MyObject()
OtherObject otherObject = myObject.Property;
DifferentObject differentObject = myObject.Property;
}

属性可以返回不同的对象类型吗?

编辑2:

在这个问题中混合了两种不同的东西。曾经有人想知道如何获得具有两种不同返回类型的属性,这是基于对DataTable的误解。

如何实现隐式强制转换

简单:不行:

Unhandled Exception: System。InvalidCastException:无法转换类型的对象"System.Data。"data . datarowview"。

然而,foreach的工作模式在某些情况下允许隐式强制转换。不管它们是否有效。在这个例子中,它不能被编译器检查,因为.Rows暴露了一个基于object的迭代器(在这个例子中,IEnumerable/IEnumerator,但即使这样也不是严格必要的)。

更一般地说,有隐式转换操作符,但它仍然不适用于基于object的迭代器,因为操作符只应用于静态已知类型(除非使用dynamic)。

GetEnumerator()方法允许访问object以外的内容的场景中,编译器可以告诉我们:

foreach (DataRowView row in dtTable.AsEnumerable())
{
}
编译器为

添加错误:

错误1无法转换类型"System.Data"。DataRow'到'System.Data.DataRowView'

虽然在这种情况下,它至少允许使用隐式操作符,如果定义的话。他们不是。


更多细节:

为什么编译?

.Rows类型为DataRowCollection。由于这可以追溯到。net 1.1,它实现了ICollectionIEnumerable,但从未更新以实现IEnumerable<DataRow>。同样地,GetEnumerator()方法返回IEnumerator——不是更具体的东西。

IEnumerator的问题(与IEnumerator<T>不同)是.Current的类型仅为object,因为。net 1.1和c# 1.2没有泛型。如果你不得不这样做,那将会非常尴尬:

foreach(object tmp in table.Rows)
{
    DataRowView row = (DataRowView)tmp; // this is our known-bad code
    // ...

所以为了方便,语言允许你隐式地执行,也就是说,上面的代码与

大致相同:
foreach(DataRowView row in table.Rows) // this is our known-bad code
{
    // ...

实际上变成了这样的东西:

{
    IEnumerator iter = table.Rows.GetEnumerator();
    // note this ^^^ is disposed after the loop if IDisposable; not shown
    while(iter.MoveNext())
    {
        DataRowView row = (DataRowView) iter.Current; // .Current is: object
        // ...
    }
}

注意到从objectDataRowView的强制转换吗?如果从.Current返回的东西实际上不是DataRowView(并且:它不是),那只会在运行时执行强制转换时失败。如果我们对DataRow而不是DataRowView做同样的事情,它就会成功。

注意foreach模式实际上并不依赖于IEnumerator;任何类型都可以有一个GetEnumerator()方法,并返回一个具有更强(类型化).Current实现的自定义迭代器类型。如果DataRowCollection这样做了,那么使用DataRowView的代码就会失败。这可以是一个完全自定义的迭代器,也可以是简单的IEnumerable<DataRow>/IEnumerator<DataRow>。考虑完全假设的情况:

{
    IEnumerator<DataRow> iter = table.Rows.GetEnumerator();
    // note this ^^^ is disposed after the loop if IDisposable; not shown
    while(iter.MoveNext())
    {
        DataRowView row = (DataRowView) iter.Current; // .Current is: DataRow
        // ...
    }
}
现在使用这个结构,我们可以看到我们从DataRow转换到DataRowView,并且是编译器可以在编译时检查的东西。由于它们是类,除非存在继承关系或自定义转换操作符,否则它将失败。