我可以为default()
设置MyClass
值吗?我的想法是,当我调用null
时返回default(MyClass)
,它返回此类的实例,但是使用默认值。
例如:
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
)的默认实例。
答案 0 :(得分:1)
这不是default
关键字的目标,我很高兴你无法重新定义它:你会让事情变得非常复杂。
default
关键字存在,因此当使用值类型(无法为空)时,您将获得默认对象状态(对于引用类型,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
实例化:
null
如果myOtherFoo.myFoo
是抽象的,Foo
的价值可能是什么(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(T)
的记录良好的行为。
如果要模拟类中结构的default(T)
行为,则只需替换new T()
的{{1}}并添加T: new()
约束。这将要求这些类具有无参数构造函数而不是抽象的,但您可以将其视为&#34; default(T)
&#34;如果你愿意实现(没有这两个约束,那么任何涉及创建实例的default()
方法都无法工作)。
在您的示例中,这将是:
class DictionaryEx<TKey, TValue>: Dictionary<TKey, TValue>
where TValue : new()
{
public TValue GetOrDefault(TKey paramKey) {
return ContainsKey(paramKey) ? this[paramKey] : new TValue();
}
}
然而,这将禁止返回null
。作为一种可能的解决方法,您可以&#34;标记&#34;你不喜欢使用空接口返回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));
}
}
然后为课程&#34;标记&#34;使用该接口,它将创建一个默认实例(使用无参数构造函数:它会抛出异常,但是没有定义),并且会为所有其他实例返回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>();
答案 1 :(得分:0)
为默认值添加 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>);
}
}