C# 何时使用运行时类型信息?

C# 何时使用运行时类型信息?,c#,c++,casting,oop,runtime-type,C#,C++,Casting,Oop,Runtime Type,如果我有一些东西的不同子类,以及一个在这些子类的实例上运行的算法,如果算法的行为根据实例的特定子类略有不同,那么最常用的面向对象方法就是使用虚拟方法 例如,如果子类是DOM节点,并且如果算法要插入子节点,则该算法根据父节点是DOM元素(可以有子节点)还是DOM文本(不能有子节点)而有所不同:因此insertChildren方法在DomNode基类中可能是虚拟的(或抽象的),并且在DomElement和DomText子类中的每一个子类中都有不同的实现 另一种可能性是为实例提供一个公共属性,该属性的

如果我有一些东西的不同子类,以及一个在这些子类的实例上运行的算法,如果算法的行为根据实例的特定子类略有不同,那么最常用的面向对象方法就是使用虚拟方法

例如,如果子类是DOM节点,并且如果算法要插入子节点,则该算法根据父节点是DOM元素(可以有子节点)还是DOM文本(不能有子节点)而有所不同:因此
insertChildren
方法在
DomNode
基类中可能是虚拟的(或抽象的),并且在
DomElement
DomText
子类中的每一个子类中都有不同的实现

另一种可能性是为实例提供一个公共属性,该属性的值可以读取:例如,算法可以读取
DomNode
基类的
nodeType
属性;或者再举一个例子,您可能有不同类型(子类)的网络数据包,它们共享一个公共数据包头,您可以读取数据包头以查看它是什么类型的数据包

我很少使用运行时类型信息,包括:

  • 在C中是
    作为
    关键字#
  • 向下投射
  • dot-net中的Object.GetType方法
  • C中的
    typeid
    运算符++
当我添加一个取决于子类类型的新算法时,我倾向于向类层次结构添加一个新的虚方法


我的问题是,什么时候使用运行时类型信息代替C++中的虚函数?

< p>,在一些其他模糊的情况下(主要是处理较差的设计选择),RTTI是一种实现所谓的. 如果我没记错的话,动态_cast取决于RTTI。当对象通过空指针时(无论出于何种原因),一些模糊的外部接口也可能依赖于RTTI


我说过,在10年的C++维护工作中,我还没有看到过野生型。(幸运的是。)

当没有其他办法的时候。虚拟方法总是首选,但有时它们就是无法使用。可能发生这种情况的原因有两个,但最常见的一个是您没有要使用的类的源代码,或者您无法更改它们。当您使用遗留系统或封闭源代码商业库时,通常会发生这种情况


在.NET中,您可能还需要动态加载新程序集,如插件,并且通常没有基类,但必须使用duck类型。

对于运行时类型检查可以的情况,您可以参考更有效的C

项目3。专门化泛型算法 使用运行时类型检查

您可以通过以下方式轻松重用泛型: 只需指定新的类型参数。 具有新类型的新实例化 参数是指具有 类似的功能

这一切都很好,因为你在写作 更少的代码。然而,有时 更一般的意思是不采取行动 优势更具体,但是 显然,算法更优越。C# 语言规则考虑到了这一点。 只要你能认出 你的算法可以更精确 当类型参数 拥有更大的能力,然后 编写特定的代码。此外,, 创建第二个泛型类型 指定不同的约束 并不总是有效的。通用的 实例化是基于 对象的编译时类型,以及 不是运行时类型。如果你不能 考虑到这一点,你可能会错过 可能的效率

例如,假设您编写了一个类,该类对IEnumerable表示的项序列提供逆序枚举。为了向后枚举它,您可以迭代它并将项复制到具有索引器访问权限(如List)的中间集合中,然后使用索引器访问向后枚举该集合。但如果您的原始IEnumerable是IList,为什么不利用它并提供更高性能的方式(无需复制到中间集合)来向后迭代项呢。因此,基本上这是一种我们可以利用的特殊方法,但仍然提供相同的行为(向后迭代序列)

<>但是一般来说,你应该仔细考虑运行时类型检查,并确保它不违反LISKOV替换原则。

< P>这种构造(“IS”和“AS”)对于Delphi开发人员来说是非常熟悉的,因为事件处理程序通常将对象降到一个共同祖先。例如,无论对象的类型是TButton、TListBox还是任何其他类型,event OnClick都会传递唯一的Argument Sender:ToObject。如果你想知道更多关于这个对象的信息,你必须通过“as”访问它,但是为了避免异常,你可以在访问之前用“is”检查它。这种向下转换允许对象和方法的设计类型绑定,这在严格的类类型检查中是不可能的。想象一下,如果用户单击按钮或列表框,您也希望执行相同的操作,但如果他们为我们提供不同的函数原型,则无法将它们绑定到相同的过程


在更一般的情况下,对象可以调用一个函数来通知对象(例如)已更改。但在这之前,目的地有可能“亲自”(通过身份和身份)认识他,但不一定。它通过将self作为所有对象(Delphi中的TObject)中最常见的祖先传递来实现这一点。

这是一种“a”方式,是的;另一种方法是使用仅使用虚拟函数的函数:您将为参数类型的每个子类添加一个新的虚拟函数。如果您查看我发布的链接,您将看到它实际上导致“多重分派”,这是双重分派的推广<代码>:)你为什么这么说