簡體   English   中英

設置默認(類)值

[英]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 ,而是返回TValueMyClass.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM