【问题标题】:Check if type TA can cast to type TB at runtime? (Considering something more than inheritance)检查类型 TA 是否可以在运行时转换为类型 TB? (考虑的不仅仅是继承)
【发布时间】:2023-03-08 08:04:01
【问题描述】:

所以我知道这是可行的:

class A
{
}
class B : A
{       
}

[Test]
public void CanCast()
{
    Assert.That(typeof(A).IsAssignableFrom(typeof(B)));
    Assert.That(!typeof(B).IsAssignableFrom(typeof(A)));
}

但是,假设这两种类型是 Int32 和 Int64。

在运行时,我可以将 Int32 值转换为 Int64 变量,但反过来不行。如何在运行时检查这种类型的转换兼容性? (IsAssignableFrom 对此不起作用,它总是为 Int32 和 Int64 提供 false)

编辑:我不能简单地尝试强制转换,因为我没有这些类型的任何值,我问的是有两种类型 A 和 B,没有两个值的假设场景a和b。

【问题讨论】:

  • 真正的问题是:在运行时,如果您无法将 Int64 转换为 Int32,您会怎么做?要么你可以解决问题,然后为什么不一直应用解决方法,这样你就不需要费心检查,或者你什么也做不了,然后为什么不让系统抛出一个还是例外?
  • 某些 int64 值适合 int32 是否相关?还是您想禁止它,因为它并不总是有效?
  • 可以Int64 转换为Int32,但这是显式转换,而不是隐式转换。对于内置类型,允许的显式和隐式转换是特定于语言的,这不是您可以从有问题的Types 中找到的。问题是,你为什么想知道这个?为什么要在运行时知道 C# 在编译时是否允许隐式转换?

标签: c# .net cil


【解决方案1】:

对于非原始类型,您可以反映和检查在任一支持转换的类型上是否存在op_Implicit 方法。 IL 实际上并不支持真正的运算符重载,因此它纯粹是 C# 识别运算符重载的约定系统。如果该方法是从 C# 中的运算符重载定义创建的,则该方法也将被标记为 IsSpecialName。

对于primitive types(如 Int32 和 Int64),最简单的选择是硬编码各种情况,因为转换是通过原始 IL 操作码而不是通过方法进行的。但是,只有少数原始类型,因此创建一个检查每种原始类型的所有可能性的方法并不难。

附带说明,因为您的示例特别提到了原始值类型,请注意隐式“转换”(在 C# 中)的存在并不意味着所有“强制转换”都可以工作。 C# 转换操作(T)x 也可以表示“将 x 中的值拆箱为类型 T”。如果 x 包含一个装箱的 Int32 并且您尝试 (Int64)x,这将在运行时失败,即使您可以将 Int32 隐式“转换”为 Int64。请参阅Eric Lippert 了解更多关于为什么以这种方式进行拆箱的信息。

【讨论】:

    【解决方案2】:

    一种(不太优雅的)方法是简单地尝试一下 - 将您的尝试包装在 try/catch 中,如果捕获到异常则断言为 false。

    【讨论】:

    • EAFP 范式:请求宽恕比请求许可更容易。如果特殊情况很少见,这通常是一个好方法。
    • 我没有说我有值,我只有类型。
    猜你喜欢
    • 2023-04-03
    • 2011-01-08
    • 1970-01-01
    • 2013-05-29
    • 2019-01-19
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多