[英]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.