Immutable Properties

Microsoft likes to say that an auto-implemented property declared with a private set accessor is immutable. This is not entirely true, in a number of ways. One can always use reflection to assign values to a property, regardless of whether the set accessor is private or public. But putting conspiracy theory cases like that to the side, these properties still cannot be considered immutable due to the fact that, although the outside world cannot set their values, they are settable from anywhere inside the class.

The only type of property I would consider immutable is one that returns a read-only field and lacks a set accessor entirely. Of course, the very field that gets returned, provided it is not a value type, may very well not be immutable itself, but I digress.

I found an interesting way to assign a value to a property declared with a private set accessor that doesn’t use reflection. It does, however require some participation from the class itself. I’m not recommending actually using the approach I’m going to go over in any real-world code, as most of the time a read-only property is read-only for a good reason. Having to skirt around accessibility levels should never be the only way to proceed with an implementation, and if it is, then there is a problem with your design or approach as a whole. But, if you know what you’re doing, this may be of interest to you.

But putting all that sensible stuff aside, I’ve found an interesting one can go about setting the value of a property with a private set accessor using Expressions. More specifically, we can take an expression of a property’s get accessor being accessed and turn it into one where a value is being assigned to the property’s set accessor. This could be useful for instances where you need to initialize some sort of domain object that features limited accessibility in regards to setting the values of its properties.

An Example: PropertyMap

I developed a PropertyMap type which allows you to define values for a type of object’s properties outside of and independent of any instance of that type. The PropertyMap is populated with values that should be set to different properties of the target type. The properties are specified through the use of an ExpressionReader class that features a ReadName method that returns the name of a member being accessed. There are plenty of examples online as to how to use Expressions in order to get the names of code elements, so I’ll defer you to those examples if you wish to learn more about this.

As a side note, before we get to the code, just note I had to condense the names of the type parameters in order for the code to fit on the page the best. Typically, they’re a bit more descriptive.

Here’s the code for the Add method:

/// <summary>
/// Adds a mapping entry for the property being expressed.
/// </summary>
/// <typeparam name="TValue">The type of value returned by the property.</typeparam>
/// <param name="propertyExpression">An expression accessing a property's getter method.</param>
/// <param name="value">
/// The value to be assigned to the property during a future mapping operation.
/// </param>
public void Add<TValue>([NotNull]Expression<Func<T,TValue>> propertyExpression, TValue value)
{
    string propertyName = ExpressionReader.ReadName(propertyExpression);

    if (!ContainsKey(propertyName))
        Add(propertyName, value);
}

Alright, nothing too crazy here.

You can then pass the PropertyMap to an instance of the targeted type, which the instance can then use to assign values to its properties via successive calls to a Map function, each time providing an expression that accesses a different property.

/// <summary>
/// Maps a preconfigured value to the property being expressed.
/// </summary>
/// <typeparam name="TValue">The type of value returned by the property.</typeparam>
/// <param name="propertyExpression">
/// An expression accessing the getter method of the property to map to.
/// </param>
public void Map<TValue>([NotNull]Expression<Func<TValue>> propertyExpression)
{
    string propertyName = ExpressionReader.ReadName(propertyExpression);

    // Validation occurs here...Excluding this from the post.

    MemberExpression propertyGetterExpression
        = (MemberExpression) propertyExpression.Body;
    ConstantExpression instanceExpression
        = (ConstantExpression) propertyGetterExpression.Expression;

    T instance = (T) instanceExpression.Value;
    Action<T, TValue> propertySetter = CompileSetter<TValue>(propertyGetterExpression);

    propertySetter(instance, (TValue) this[propertyName]);
}

The above extracts the property getter expression and then calls CompileSetter to create an Action that invokes the set accessor of the type.

/// <summary>
/// Compiles a property setter method derived from the provided property getter expression.
/// </summary>
/// <typeparam name="TValue">The type of value returned by the property.</typeparam>
/// <param name="propertyGetterExpression">
/// An expression accessing a property's getter method.
/// </param>
/// <returns>
/// A compiled <see cref="Action{T,TValue}"/> which will set the value of the property
/// accessed by
/// <c>propertyGetterExpression</c> to what's provided.
/// </returns>
private static Action<T, TValue> CompileSetter<TValue>(Expression propertyGetterExpression)
{
    ParameterExpression valueParameterExpression
        = Expression.Parameter(typeof (TValue), "value");
    ParameterExpression instanceParameterExpression
        = Expression.Parameter(typeof (T), "x");

    BinaryExpression assignValueExpression
        = Expression.Assign(propertyGetterExpression, valueParameter);

    Expression<Action<T, TValue>> propertySetterExpression
        = Expression.Lambda<Action<T, TValue>>(assignValueExpression,
                                               instanceParameterExpression,
                                               valueParameterExpression);
    return propertySetterExpression.Compile();
}

Let’s go over a very rough example of this in action. Here’s the participating class:

public class Example
{
    public string Label
    { get; private set; }

    public void Map(PropertyMap<Example> map)
    {
        map.Map(() => Label);
    }
}

And here’s an example of invoking that class:

PropertyMap<Example> map = new PropertyMap<Example>
                {
                    { x => x.Label, "This works!" }
                };

Example example = new Example();

example.Map(map);

// The string variable below will be set to "This works!"
string label = example.Label;

I was initially somewhat surprised that this worked, we are basically changing the x => x.Label expression into a (x,value) => x.Label = value expression. Obviously this all fails if there is no set accessor at all.

The reasons why this works is something I’ll cover in another post in the future.

Should I Use This in My Code?

If you are unsure and have to ask me, then no, you shouldn’t use this in your code. For most cases where you could use this, you would be at best clever, and at worst irresponsible; however, for some situations, this could be considered an appropriate approach. Going into what those specific situations might be is far and beyond outside the scope of this article.

Matt Weber

I'm the founder of Bad Echo LLC, which offers consulting services to clients who need an expert in C#, WPF, Outlook, and other advanced .NET related areas. I enjoy well-designed code, independent thought, and the application of rationality in general. You can reach me at matt@badecho.com.

  2 Responses to “Writing to a Property with a Private Set Accessor”

  1. What’s that argument attribute? And why I’ve never seen this before?

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
   
© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.