Friday, January 23, 2009

A thought on how to hide private backing field

Ever thought of forcing every piece of code in your class to access information about your object via properties instead of fields? Imagine you build a type where you have some logic inside your property that you always want to run.

private string _myField;

public string MyField
{
	get { return _myField; }
	set { 
		if (_myField == value)
			return;

		_myField = value; 
		
		RaisePropertyChanged("MyField");
	}
}
In this classic case of property change notification, nothing prevent anyone to write this somewhere in the class:
_myField = "Something";
…and no PropertyChanged event fires.

Does everybody know about auto-properties?

public string MyField { get; set; }

If you look at the reflected code (with reflector):

[CompilerGenerated]
private string <MyField>k__BackingField;

[CompilerGenerated]
public void set_MyField(string value)
{
    this.<MyField>k__BackingField = value;
}

[CompilerGenerated]
public string get_MyField()
{
    return this.<MyField>k__BackingField;
}

You can see that the field defined at line 2 is written in an invalid C# syntax but it is valid in IL:

.field private string <MyField>k__BackingField
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
}

.method public hidebysig specialname instance void set_MyField(string 'value') cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: stfld string PropertyHideBackingFieldTest.Class1::<MyField>k__BackingField
    L_0007: ret 
}

.method public hidebysig specialname instance string get_MyField() cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
    .maxstack 1
    .locals init (
        [0] string str)
    L_0000: ldarg.0 
    L_0001: ldfld string PropertyHideBackingFieldTest.Class1::<MyField>k__BackingField
    L_0006: stloc.0 
    L_0007: br.s L_0009
    L_0009: ldloc.0 
    L_000a: ret 
}
 

Here is my idea. If we can write code like this:

public string MyField
{
	field string _myField;
	
	get { return _myField; }
	set { 
		if (_myField == value)
			return;

		_myField = value; 
		
		RaisePropertyChanged("MyField");
	}
}

Now we can build a private field that won’t be available anywhere else. We will now have full control over the field itself. Maybe it can be available to the constructor too.

Or if we can at least have an attribute to do that. Like this:

[PropertyAccessOnly]
private string MyField;
Let me know what you think.

3 comments:

Anonymous said...

Hi Eric,

I need a small C# project with before and after code to understand your idea...this is over my head. But if you have a project I can run, it will be much easier...then I can debug the code and run it till I get the idea...

Nice of you to share code idea!

Thank you,
Rune

meh said...

That would be great, however... it must stay accessible from the constructor.

If you think about it, there should be no reason to access _myField from outside the property.

Cheers

Eric De C# said...

Rune, this is juste an idea. Nothing like that exist yet. This is why I can't give you a full code sample.