如何对支持null的引用类型和值类型进行类型测试?
How can I implement type testing for reference types and value types supporting null?
我尝试实现支持 null 的类型测试。
我有两个通用函数:
public static int FromValueType<T>(T? o) where T : struct { /* do stuff */ return 1; }
public static int FromClassType<T>(T o) where T : class { /* do stuff */ return 2; }
我理解这两个都不支持null
,因为编译器无法从null
推断出T
。例如,此调用将不起作用:
var x = FromClassType(null);
这就是为什么我想编写一个包装器来实现类型测试以扩展 null
的功能。
到目前为止我尝试了什么:
public static int From(object o)
{
return o switch
{
null => 0,
/**
* TODO: Compiler complains:
* The type arguments for method 'int MyModule.FromValueType<T>(T?)'
* cannot be inferred from the usage. Try specifying the type arguments
* explicitly.
*/
ValueType oValueType => FromValueType(oValueType),
_ => FromClassType(o)
};
}
但这也不行。
如果 ValueType
是所有值类型的基础 class,为什么编译器不能推断 T
?
System.ValueType
是引用类型。因此编译无法推断出匹配的版本:
public static int FromValueType<T>(T? o) where T : struct { /* do stuff */ return 1; }
据我所知,所有值类型都不存在共同的基类型。这意味着我们必须在运行时使用反射来构建和调用 FromValueType
:
public static int From(object o)
{
return o switch
{
null => 0,
ValueType oValueType => (int) typeof(ClassWithFromValueTypeMethod)
.GetMethod(nameof(FromValueType))
?.MakeGenericMethod(oValueType.GetType())
.Invoke(null, new []{o}),
_ => FromClassType(o)
};
}
在这种情况下使用反射可能不是最佳选择,但这是我能看到的唯一无需重构即可工作的解决方案 FromValueType
和 FromClassType
.
如果我们可以重构 FromValueType
和 FromClassType
。最好简单地从 From
包装器中的两个逻辑移动:
public static int From<T>(T o)
{
if (o == null) return 0;
return typeof(T).IsValueType
? 1 // FromValueType
: 2; // FromClassType
}
请注意,根据 FromValueType
和 FromClassType
的复杂性,就可测试性和可维护性而言,这可能不是一个理想的解决方案。它也不支持用 null
调用它。为了支持这一点,我们必须再次进行一些运行时类型检查:
public static int From(object o)
{
if (o == null) return 0;
return o.GetType().IsValueType
? 1 // FromValueType
: 2; // FromClassType
}
感谢@JonSkeet 的有用评论。
我尝试实现支持 null 的类型测试。
我有两个通用函数:
public static int FromValueType<T>(T? o) where T : struct { /* do stuff */ return 1; }
public static int FromClassType<T>(T o) where T : class { /* do stuff */ return 2; }
我理解这两个都不支持null
,因为编译器无法从null
推断出T
。例如,此调用将不起作用:
var x = FromClassType(null);
这就是为什么我想编写一个包装器来实现类型测试以扩展 null
的功能。
到目前为止我尝试了什么:
public static int From(object o)
{
return o switch
{
null => 0,
/**
* TODO: Compiler complains:
* The type arguments for method 'int MyModule.FromValueType<T>(T?)'
* cannot be inferred from the usage. Try specifying the type arguments
* explicitly.
*/
ValueType oValueType => FromValueType(oValueType),
_ => FromClassType(o)
};
}
但这也不行。
如果 ValueType
是所有值类型的基础 class,为什么编译器不能推断 T
?
System.ValueType
是引用类型。因此编译无法推断出匹配的版本:
public static int FromValueType<T>(T? o) where T : struct { /* do stuff */ return 1; }
据我所知,所有值类型都不存在共同的基类型。这意味着我们必须在运行时使用反射来构建和调用 FromValueType
:
public static int From(object o)
{
return o switch
{
null => 0,
ValueType oValueType => (int) typeof(ClassWithFromValueTypeMethod)
.GetMethod(nameof(FromValueType))
?.MakeGenericMethod(oValueType.GetType())
.Invoke(null, new []{o}),
_ => FromClassType(o)
};
}
在这种情况下使用反射可能不是最佳选择,但这是我能看到的唯一无需重构即可工作的解决方案 FromValueType
和 FromClassType
.
如果我们可以重构 FromValueType
和 FromClassType
。最好简单地从 From
包装器中的两个逻辑移动:
public static int From<T>(T o)
{
if (o == null) return 0;
return typeof(T).IsValueType
? 1 // FromValueType
: 2; // FromClassType
}
请注意,根据 FromValueType
和 FromClassType
的复杂性,就可测试性和可维护性而言,这可能不是一个理想的解决方案。它也不支持用 null
调用它。为了支持这一点,我们必须再次进行一些运行时类型检查:
public static int From(object o)
{
if (o == null) return 0;
return o.GetType().IsValueType
? 1 // FromValueType
: 2; // FromClassType
}
感谢@JonSkeet 的有用评论。