如何实现隐式强制转换
本文关键字:转换 何实现 实现 | 更新日期: 2023-09-27 18:11:17
我看到一些属性允许为casted implicitly
。像DataTable.Rows
一样,可以在DataRow
和DateRowView
中浇注。
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,它实现了ICollection
和IEnumerable
,但从未更新以实现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
// ...
}
}
注意到从object
到DataRowView
的强制转换吗?如果从.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
,并且是编译器可以在编译时检查的东西。由于它们是类,除非存在继承关系或自定义转换操作符,否则它将失败。