设置默认(类)值
本文关键字:默认 设置 | 更新日期: 2024-09-24 22:22:12
是否可以为MyClass
设置default()
值?我的想法是,如果在调用default(MyClass)
时返回null
,它将返回该类的一个实例,但使用默认值。
例如:
class MyClass {
// Default value.
static public readonly MyClass Default = new MyClass();
}
所以当我打电话时: nbsp 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);
您刚刚创建了一个无休止的初始化循环。
当然,这可以是静态和运行时分析的,也可以是编译时错误(比如在同一结构类型定义中定义结构字段的错误)和运行时异常。。。但你只是剥夺了CCD_ 26有充分记录的行为。
可能的解决方法
如果您想在类的结构中模拟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的类,并且在类型实现该接口时使用Activator.CreateInstance()
,而不是使用new()
约束,否则返回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>();
Fiddle here: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>);
}
}