繁体   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