[英]Setting the default(class) value
我可以為MyClass
設置default()
值嗎? 我的想法是,如果在調用default(MyClass)
時返回null
,它將返回此類的實例,但具有默認值。
例如:
class MyClass {
// Default value.
static public readonly MyClass Default = new MyClass();
}
所以當我調用時: var defaultValue = default(MyClass);
它類似於: var defaultValue = MyClass.Default;
我需要將它與泛型一起使用:
class DictionaryEx<TKey, TValue>: Dictionary<TKey, TValue> {
public TValue GetOrNull(TKey paramKey) {
return ContainsKey(paramKey) ? this[paramKey] : default(TValue);
}
}
因此,如果我使用帶有不存在鍵的GetOrNull()
,它將不會返回null
,而是返回TValue
( MyClass.Default
)的默認實例。
這不是default
關鍵字的目標,我很高興你無法重新定義它:你會讓事情變得非常復雜。
default
關鍵字是存在的,因此當使用值類型(不能為null)時,您將獲得默認對象狀態(對於引用類型,null,對於值類型,無參數構造函數狀態)。 這是一個明確定義的行為,如果你改變它,你可能會引起很多悲傷。
如果你沒有定義一個值類型有一個隱式公共無參數構造函數(所以default(T)
實際上可以返回一個值),其中所有的字段都被初始化為它們的default()
如果你想要檢查它:定義一個struct
帶有一個帶參數但沒有無參數構造函數的構造函數,並嘗試new myStruct()
:它編譯並工作)。 對於引用類型不是這種情況......如果一個類沒有明確的公共無參數構造函數(或者根本沒有定義構造函數),那么沒有辦法可以在沒有參數的情況下實例化它。
考慮一下,如果您更改了default()
實現,這段代碼可以做什么(將默認實現語法作為偽代碼)?
public abstract class Foo
{
protected Foo(int x)
{
}
protected override Foo default()
{
return new Foo(50); // You can't instantiate an abstract class
}
}
//..
Foo myFoo = default(Foo);
如果它是抽象的,那么default(Foo)
如何假設實例化Foo
? 但是為了使它更復雜......想象你有這個值類型,需要 - 能夠使用default()
實例化:
public struct Bar
{
public Foo myFoo;
}
//
var myBar = default(Bar); // this just can't return null since
// Bar is a value type
如果Foo
是抽象的, myOtherFoo.myFoo
的值是什么(除了null
)?
但是讓我們更容易並從問題中abstract
出來(假設它不會讓你在抽象類中更改default()
並且會給編譯器錯誤),並考慮這種情況:
public class Foo
{
public Bar myBar;
protected override Foo default()
{
return new Foo();
}
}
public struct Bar
{
public Foo myFoo;
}
var myBar = default(Bar);
您剛剛創建了無限的初始化循環。
這當然可以是靜態和運行時分析,並且編譯時錯誤(比如在同一結構類型定義中定義結構字段的那些)和運行時異常都可能被拋出......但是你只是把它帶走了 - 記錄的default()
行為default()
。
如果要在類上的結構中模擬default(T)
的行為,則只需將default(T)
替換為new T()
並添加T: new()
約束。 這將要求這些類具有無參數構造函數而不是抽象的,但如果您願意,可以將其視為“ default(T)
”實現(沒有這兩個約束,就沒有任何default()
方法涉及創建實例也可以工作。
在您的示例中,這將是:
class DictionaryEx<TKey, TValue>: Dictionary<TKey, TValue>
where TValue : new()
{
public TValue GetOrDefault(TKey paramKey) {
return ContainsKey(paramKey) ? this[paramKey] : new TValue();
}
}
但是,這將禁止返回null
。 作為一種可能的解決方法,您可以“標記”您不希望使用空接口返回null的類,而不是使用new()
約束,當類型實現該接口時使用Activator.CreateInstance()
,或者返回否則為null ...類似於:
interface IWithExplicitParameterLessConstructor {}
class DictionaryEx<TKey, TValue>: Dictionary<TKey, TValue>
{
public TValue GetOrDefault(TKey paramKey) {
return ContainsKey(paramKey) ? this[paramKey] :
(typeof(IWithExplicitParameterLessConstructor).IsAssignableFrom(typeof(TValue)) ? Activator.CreateInstance<TValue>() : default(TValue));
}
}
然后對於使用該接口“標記”的類,它將創建一個默認實例(使用無參數構造函數:它將拋出異常,無定義),並且將為所有其他實例返回null
(以及值的相應默認值)類型)。
否則,如果你需要能夠擁有一個沒有公共無參數構造函數的default
實例值(從遠處聞到),你可以在代碼中記錄一個約定,並使用反射在類中查找靜態屬性值或靜態方法類型。 如上所述,這聞起來很遠,我絕對不推薦它,但它是可行的:
public static class GetDefaultHelper
{
public static T GetDefaultInstance<T>()
{
var propInfo = typeof(T).GetProperty("Default", BindingFlags.Public | BindingFlags.Static);
return (propInfo != null) ? (T)propInfo.GetValue(null) : default(T);
}
}
並使用它像:
Foo foo = GetDefaultHelper.GetDefaultInstance<Foo>();
在這里小提琴: https : //dotnetfiddle.net/JO8YfV
添加TValue類型的新參數作為默認值。
public class DictionaryEx<TKey, TValue> : Dictionary<TKey, TValue>
{
public TValue GetValueOrDefault(TKey paramKey, TValue @default)
{
TValue value;
if (TryGetValue(paramKey, out value))
return value;
return @default;
}
}
解決方案2:
public class DictionaryEx<TKey, TValue> : Dictionary<TKey, TValue>
{
public TValue GetValueOrDefault(TKey paramKey, Func<TValue> funcDefault)
{
TValue value;
if (TryGetValue(paramKey, out value))
return value;
return funcDefault();
}
public TValue GetValueOrDefault(TKey paramKey)
{
return GetValueOrDefault(paramKey, Activator.CreateInstance<TValue>);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.