I know that I can use the verbose syntax for properties:
private string _postalCode; public string PostalCode { get { return _postalCode; } set { _postalCode = value; } }
Or I can use auto-implemented properties.
public string PostalCode { get; set; }
Can I somehow access the backing field that is behind the auto-implemented property? (In this example that would be _postalCode).
Edit: My question is not about design, but rather about, let's say, theoretical ability to do so.
Auto-implemented properties declare a private instance backing field, and interfaces may not declare instance fields. Declaring a property in an interface without defining a body declares a property with accessors that must be implemented by each type that implements that interface.
Auto-implemented properties enable you to quickly specify a property of a class without having to write code to Get and Set the property.
A private field that stores the data exposed by a public property is called a backing store or backing field. Fields typically store the data that must be accessible to more than one type method and must be stored for longer than the lifetime of any single method.
Properties enable a class to expose a public way of getting and setting values, while hiding implementation or verification code. A get property accessor is used to return the property value, and a set property accessor is used to assign a new value.
I don't know about you, but I've written code in projects in other companies, and now I want to know how I did something! So it's usually quicker to do a web search for the answer, and it brought me here.
However, my reasons are different. I'm unit testing, and don't care what purists have to say, but as part of a setup for a unit test, I'm trying to invoke a certain state for a given object. But that state should be controlled internally. I don't want some other developer accidentally messing with the state, which could have far reaching effects upon the system. So it must be privately set! Yet how do you unit test something like that without invoking behaviours that (hopefully) will never happen? In such scenarios, I believe that using reflection with unit testing is useful.
The alternative is to expose things we don't want exposed, so we can unit test them! Yes, I've seen this in real life environments, and just thinking about it still makes me shake my head.
So, I'm hoping that the code below might be useful.
There are two methods here just for separation of concerns, really, and also to aid in readability. Reflection is head-spinning stuff for most developers, who in my experience either shy away from it, or avoid it like the plague!
private string _getBackingFieldName(string propertyName) { return string.Format("<{0}>k__BackingField", propertyName); } private FieldInfo _getBackingField(object obj, string propertyName) { return obj.GetType().GetField(_getBackingFieldName(propertyName), BindingFlags.Instance | BindingFlags.NonPublic); }
I don't know what code conventions you work to, but personally, I like helper methods to be private and begin with a lower case letter. I don't find that obvious enough when reading, so I like the preceding underscore too.
There is discussion of backing fields, and their automatic naming. For the purpose of unit tests, you'll know pretty quickly if it has changed or not! It won't be catastrophic to your real code either, just the tests. So we can make simple assumptions about the naming of names—as I have above. You may disagree, and that's fine.
The more difficult helper _getBackingField
returns one of those reflection types, FieldInfo
. I've made an assumption here too, that the backing field you're after is from an object that's an instance, as opposed to being static. You can break that out into arguments to be passed in if you wish, but the waters will sure be muddier to the average developer who might want the functionality but not the understanding.
The handy thing about FieldInfo
s is that they can set fields on objects that match the FieldInfo
. This is better explained with an example:
var field = _getBackingField(myObjectToChange, "State"); field.SetValue(myObjectToChange, ObjectState.Active);
In this case, the field is of an enumeration type called ObjectState
. Names have been changed to protect the innocent! So, in the second line, you can see that by accessing the FieldInfo
returned previously, I can call upon the SetValue
method, which you might think should already relate to your object, but does not! This is the nature of reflection—FieldInfo
separates a field from where it came from, so you must tell it what instance to work with (myObjectToChange
) and thus, the value you want it to have, in this case, ObjectState.Active
.
So to make a long story short, object-oriented programming will prevent us from doing such nasty things as accessing private fields, and worse, changing them when the developer of the code did not intend. Which is good! That's one of the reasons C# is so valuable, and liked by developers.
However, Microsoft gave us Reflection, and through it, we wield a mighty weapon. It may be ugly, and very slow, but at the same time, it exposes the innermost depths of the inner workings of MSIL (MicroSoft Intermediate Language)—IL for short—and enables us to pretty much break every rule in the book, this being a good example.
UPDATE: https://github.com/jbevain/mono.reflection comes with a backing-field resolver method which works with auto-properties generated by C#, VB.NET, and F#. The NuGet package is at https://www.nuget.org/packages/Mono.Reflection/
ORIGINAL: I ended up with this fairly flexible method for only C# auto-properties. As the other answers make clear, this is not portable and won't work if the compiler implementation uses a backing field naming scheme other than <PropertyName>k__BackingField
. As far as I've seen, all implementations of C# compilers currently use this naming scheme. VB.NET and F# compilers use another naming scheme that won't work with this code.
private static FieldInfo GetBackingField(PropertyInfo pi) { if (!pi.CanRead || !pi.GetGetMethod(nonPublic:true).IsDefined(typeof(CompilerGeneratedAttribute), inherit:true)) return null; var backingField = pi.DeclaringType.GetField($"<{pi.Name}>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (backingField == null) return null; if (!backingField.IsDefined(typeof(CompilerGeneratedAttribute), inherit:true)) return null; return backingField; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With