Auto properties with setter blocks
See original GitHub issueI have always wanted to be able to write a setter block with auto properties. My reasoning below with proposed implementation:
public class SomeClass
{
//traditional auto property
public string Prop1 { get; set; }
//property with logic in setter. must use private field (cant use auto property)
private string _prop2;
public string Prop2
{
get
{
return _prop2;
}
set
{
//do some sort of validation (null check, length, etc)
if(value == null || value.Length > 50)
{
throw new ArgumentException();
}
_prop2 = value;
}
}
public void SomeMethod()
{
//can modify _prop2 without going through Prop2 property setter.
_prop2 = "I can set this to whatever and avoid the setter block";
}
}
The root problems is the necessity to create a field for a property when a get or set block needs to be defined. I’d like to see that necessity removed. The following code would become valid, and a new keyword would likely need to be added. I like this because it is succinct and concise:
public class SomeClass
{
//traditional auto property
public string Prop1 { get; set; }
//property with logic in setter with auto property syntax
public string Prop2
{
get;
set
{
//do something before setting the value.
if(value == null || value.Length > 50)
{
throw new ArgumentException();
}
//innervalue would be the new keyword which represents the behind-the-scenes field
innervalue = value;
//or even:
value = value;
}
}
public void SomeMethod()
{
//cannot modify Prop2 or wrapped field without going through Prop2 property setter.
Prop2 = "all access must go through setter";
}
}
This feature could be applied to getter as well where you can provide a getter body but use auto property syntax for the setter, although I personally can’t think of a good reason to do that.
innervalue
would be a new keyword, although it seems as that the compiler should be able to reason that if value
is the target of an assignment then it would behave like innervalue
behaves. Although value = value;
seems strange since value
means different things on opposite sides of the =
and counter to how that statement would be evaluated a different context like a constructor or method body.
I would guess that the compiler would be able to reason about the above case and know that since the get uses the auto property syntax but the setter does not, then the innervalue
keyword would be available and understood.
However in a case where both the get and set have a body defined, I’m not sure how the compiler would know whether to implement innervalue or not, or whether it should implement an inaccessible field that is only accessible in the get and set blocks of the property. To solve that problem I could see another keyword (yikes!) to be added. auto get
or autoget
could work.
public string Prop1
{
auto get { /*body here*/ }
auto set { /*body here*/ }
}
Another way to accomplish is to put the field in the scope of the property like below. I don’t like this one because you have to create the field, and give it a name which is redundant, and you have provide an implementation for the get and set. It is too verbose.
public string Prop1
{
string _prop1;
get
{
return _prop1;
}
set
{
_prop1 = value;
}
}
public string Prop2
{
//cannot access _prop1
get {...}
set {...}
}
It also feels like accessibility would not be a problem either.
public string Prop2
{
get;
private set
{
//do something before setting the value.
if(value == null || value.Length > 50)
{
throw new ArgumentException();
}
//innervalue would be the new keyword which represents the behind-the-scenes field
innervalue = value;
//or even:
value = value;
}
}
Issue Analytics
- State:
- Created 9 years ago
- Comments:17 (4 by maintainers)
Top GitHub Comments
What if you would return the value at the end of your set {} block, and use that to update the backing field instead?
And maybe we could use the expression format here as well, could be useful for small but custom setters?
Using a backing field without naming it was considered in https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-01.md