我嘗試實作支持 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因為編譯器無法T從null. 例如,此呼叫將不起作用:
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是所有值型別的基類,為什么編譯器不能推斷T?
uj5u.com熱心網友回復:
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這可能是在可測驗性和maintainabilty方面不太理想的解決方案。它也不支持用null. 為了支持這一點,我們必須再次進行一些運行時型別檢查:
public static int From(object o)
{
if (o == null) return 0;
return o.GetType().IsValueType
? 1 // FromValueType
: 2; // FromClassType
}
謝謝@JonSkeet 的有用評論。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/363430.html
