C# 中有没有办法访问抽象类中定义的非
static
、非const
属性的默认值?
例如,给定:
public abstract class SomeClass
{
public int SomeProperty { get; set; } = 99;
}
我希望类似以下内容返回“
99
”:
default(SomeClass.SomeProperty);
我知道
default()
运算符不能像这样工作,上面的结果会导致编译器错误。 default()
操作符可以做的是返回SomeClass
的默认值,对于引用类型来说自然是null
,因此:
default(Test).SomeProperty;
可以编译,但会正确抛出
NullReferenceException
。
我很乐意了解以性能为代价的解决方法,例如使用反射。请注意,对于这个问题的上下文,我们需要考虑抽象类没有可用的具体实现。
我已经想象主要问题的答案是“不”。然而,如果能够从专家那里获得见解,了解该功能是否可以(或已经)考虑在 C# 中实现,或者是否存在会阻止其工作的内在语言限制,或者仅仅是它会具有以下方面的见解,那就太好了需求太稀缺,无法证明实施的合理性。
访问此
= 99
需要:
protobuf-net.BuildTools 中看到一个示例,它会检查此用法,并在没有匹配的 [DefaultValue(...)]
时引发一个标志; a
[DefaultValue(...)]
在运行时检查很简单。
public abstract class SomeClass
{
public const int SomePropertyDefault = 99;
public int SomeProperty { get; set; } = SomePropertyDefault;
}
然后您可以通过 SomeClass.SomePropertyDefault
访问它。如果由于某种原因你不能,那么你可以创建自己的派生类并实例化它:
public class TestChild : SomeClass
{
}
然后使用它 - var defaultVal = new TestChild().SomeProperty;
。除此之外,在不更改代码的情况下没有太多“简单”选项,因为默认值被编译到构造函数调用的一部分中。来自
反编译@sharplab.io:
.method family hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2061
// Code size 15 (0xf)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.s 99 // 99
IL_0003: stfld int32 SomeClass::'<SomeProperty>k__BackingField' // assign 99 to backing field
IL_0008: ldarg.0
IL_0009: call instance void [System.Runtime]System.Object::.ctor()
IL_000e: ret
} // end of method SomeClass::.ctor