如何在C#中检查运行时类型的可分配性?

epi*_*ile 10 c# types

Type类有一个几乎可以工作的方法IsAssignableFrom().不幸的是,只有当两种类型相同或第一种类型在第二种类型的层次结构中时,它才会返回true.它说十进制不能从int赋值,但是我想要一个方法来指示小数可以从int分配,但是int并不总是可以从小数分配.编译器知道这一点,但我需要在运行时解决这个问题.

这是一个扩展方法的测试.

    [Test]
    public void DecimalsShouldReallyBeAssignableFromInts()
    {
        Assert.IsTrue(typeof(decimal).IsReallyAssignableFrom(typeof(int)));
        Assert.IsFalse(typeof(int).IsReallyAssignableFrom(typeof(decimal)));
    }
Run Code Online (Sandbox Code Playgroud)

有没有办法实现IsReallyAssignableFrom(),它可以像IsAssignableFrom()一样运行,但也传递上面的测试用例?

谢谢!

编辑:

这基本上就是它的使用方式.这个例子不能为我编译,所以我必须将Number设置为0(而不是0.0M).

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
    public class MyAttribute : Attribute
    {
        public object Default { get; set; }
    }

    public class MyClass
    {
        public MyClass([MyAttribute(Default= 0.0M)] decimal number)
        {
            Console.WriteLine(number);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我收到此错误:错误4属性参数必须是属性参数类型的常量表达式,typeof表达式或数组创建表达式

Tim*_*mwi 14

在你正在寻找的意义上,实际上有三种方式可以将一种类型"分配"给另一种类型.

  • 类层次结构,接口实现,协方差和逆变.这是.IsAssignableFrom已经检查的内容.(这也包括允许装箱操作,例如intobjectDateTimeValueType).

  • 用户定义的隐式转换.这就是所有其他答案所指的内容.您可以通过Reflection检索这些,例如隐式转换为intto decimal是一个静态方法,如下所示:

    System.Decimal op_Implicit(Int32)
    
    Run Code Online (Sandbox Code Playgroud)

    您只需要检查两个相关类型(在这种情况下,Int32Decimal); 如果转换不在那些中,则它不存在.

  • 内置的隐式转换,在C#语言规范中定义.不幸的是,Reflection没有显示这些.您必须在规范中找到它们并手动将可分配性规则复制到您的代码中.这包括数字转换,例如intlong以及floatdouble,指针转换,可空转换(intint?),和解除转换.

此外,用户定义的隐式转换可以使用内置隐式转换进行链接.例如,如果用户定义的隐式转换存在于int某种类型T,那么它也会转换为转换shortT.同样,Tshort兼作Tint.

  • @epicsmile:你需要在*other*类型上检查`op_Implicit`,对于那个,查看它的返回类型而不是它的参数类型. (2认同)
  • 您省略了指针转换。您还省略了提升和可为空的转换。此外,即使不考虑提升,用户定义的隐式转换也比您的简短草图所允许的要复杂得多。例如,从 int 到 Foo 的用户定义的隐式转换也可以用作从 short 到 Foo 的用户定义的隐式转换,因为 short 转为 int 而 int 转为 Foo。 (2认同)
  • @Eric Lippert:你为什么不发表自己更完整的答案?我会赞成它. (2认同)