public class Foo<T> { internal Foo() { } }
public sealed class Foo_SByte : Foo<SByte> { }
public sealed class Foo_Byte : Foo<Byte> { }
public sealed class Foo_Short : Foo<Int16> { }
public sealed class Foo_UShort : Foo<UInt16> { }
public sealed class Foo_Int : Foo<Int32> { }
public sealed class Foo_UInt : Foo<UInt32> { }
public sealed class Foo_Long : Foo<Int64> { }
public sealed class Foo_ULong : Foo<UInt64> { }
public sealed class Foo_Char : Foo<Char> { }
public sealed class Foo_Float : Foo<Single> { }
public sealed class Foo_Double : Foo<Double> { }
public sealed class Foo_Bool : Foo<Boolean> { }
public sealed class Foo_Decimal : Foo<Decimal> { }
public sealed class Foo_String: Foo<string> { }
public class Foo_Struct<T> : Foo<T> where T : struct { }
public class Foo_Enum<T> : Foo<T> where T : Enum { }
// Now T is immutable
我的目標是將 Foo 的使用限制為所有潛在的值型別,我在語意上(可能不正確)假設相當于說“所有不可變型別”
換句話說,我不希望 T 成為參考型別。
實作在Bars. 我只希望 T 的保證僅限于不可變型別。
我錯過了任何(不包括我知道的簡單型別)嗎?
有沒有更好的辦法?
編輯:好的,我完全實作了它。現在所有的使用Foo<T>都保證是不可變的。(如果沒有,請告訴我我錯過了哪些型別。或者嘗試從 Foo 繼承來證明我錯了)。
uj5u.com熱心網友回復:
無論是在編譯時還是在運行時,都無法檢查不變性。您可以獲得的最接近的方法是檢測型別是否具有復制語意(即,如果分配x = y將導致x具有獨立于y被更改的值 - 有點,請繼續閱讀),因為有效的型別串列 (內在)復制語意在 C# 中受到限制。因此,您可以對此進行運行時檢查:
class Foo<T> {
public Foo() {
if (!(typeof(T).IsValueType || typeof(T) == typeof(string))) {
throw new ArgumentException($"{typeof(T)} does not have copy semantics.");
}
}
}
從概念上講,每次Foo<T>實體化 a 時都會進行此檢查,但實際上 JIT 可以將其優化掉。
請注意,僅具有復制語意仍然不能保證狀態的正確性。特別是,用戶定義的值型別可以參考實體外部的狀態。簡單的例子:
struct SneakyStruct {
static int i = 0;
public int Value => i ;
}
SneakyStruct您可以復制并且無法從外部修改狀態的事實仍然無助于保證您Value每次都會得到相同的結果。當然,這個例子是故意反常的,但仍然應該注意不要依賴你不必依賴的東西,或者實際上不能依賴的東西。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438282.html
