0

Is there a way in C# to access the default value of a non-static, non-const property that is defined in an abstract class?

For example, given:

public abstract class SomeClass
{
    public int SomeProperty { get; set; } = 99;
}

I would like something similar to the following to return "99":

default(SomeClass.SomeProperty);

I know that the default() operator doesn't work like this and the above results in compiler error. What the default() operator can do is return the default value for SomeClass, which naturally is null for reference types, therefore:

default(Test).SomeProperty;

can be compiled but rightly throws a NullReferenceException.

Note some assumptions for the context of this question:

  • the abstract class definition is not easily modifiable by me. It sits in an external library, to which I can propose changes, but it takes a long process of review/justification to apply such changes. This is why I would much favour solutions that do not require its modification.
    I still appreciate suggestions that could work by modifying it. I have already considered using an Attribute to store the default value and fetching it via Reflection.
  • Please consider that there is no available concrete implementation of the abstract class.

I already imagine that the answer to the main question is "no". However, it would be great to get insights from experts as per whether a feature for this could be (or has been) considered for implementation in C#, or if there are intrinsic language limitations that would prevent it from working, or simply it would have too scarce demand to justify an implementation.

6
  • 1
    Have you considered creating a constant or static property, then initialising SomeProperty to that? Commented Jan 31, 2024 at 11:22
  • So how else would it be initialised then? Commented Jan 31, 2024 at 11:23
  • @JohnathanBarclay The property cannot be a compile time constant or static. Thanks for highlighting that, I'll add this restriction to the question text. The point of the question is exactly that: to be able to access the default value (as written in the code) for the abstract class property. I know this is unusual, hence my post. Commented Jan 31, 2024 at 11:24
  • 2
    I'm not referring to the property, but the value. For example: public abstract class SomeClass { public const int Default = 99; public int SomeProperty { get; set; } = Default; }. If you could do that, then you could obtain the value of SomeClass.Default. Commented Jan 31, 2024 at 11:30
  • Why do you need the default value? And is there a specific reason you don't want or can't just apply a [DefaultValue(99)] attribute to the property? The attribute can be read easily by reflection. This is normally used by text-based serializers so they can omit serializing the property if its value is the same as the default value. Commented Jan 31, 2024 at 11:30

2 Answers 2

2

Accessing this = 99 would require either:

  1. using a Roslyn analyzer and inspecting the source at build-time
  2. reading the IL of the constructor body at runtime, and interpreting the opcodes

The first option is probably easier; you can see an example of this in protobuf-net.BuildTools, which checks for this usage, and raises a flag if there is not a matching [DefaultValue(...)]; a [DefaultValue(...)] is trivial to inspect at runtime.

Sign up to request clarification or add additional context in comments.

Comments

1

You can move the value to a constant:

public abstract class SomeClass
{
    public const int SomePropertyDefault = 99;
    public int SomeProperty { get; set; } = SomePropertyDefault;
}

Then you can access it as SomeClass.SomePropertyDefault.

If for some reason you can't then you can create your own derived class and instantiate it:

public class TestChild : SomeClass
{
}

and just use it - var defaultVal = new TestChild().SomeProperty;.

Other than that there is not much "easy" options without changing the code since the default value is compiled into part of the constructor invocation. From decompilation @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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.