views:

59

answers:

1

I'm running into an issue with private setters when using NHibernate and lazy-loading. Let's say I have a class that looks like this:

public class User
{
    public virtual int Foo {get; private set;}
    public virtual IList<User> Friends {get; set;}

    public virtual void SetFirstFriendsFoo()
    {
        // This line works in a unit test but does nothing during a live run with
        // a lazy-loaded Friends list
        Friends(0).Foo = 1; 
    }
}

The SetFirstFriendsFoo call works perfectly inside a unit test (as it should since objects of the same type can access each others private properties).

However, when running live with a lazy-loaded Friends list, the SetFirstFriendsFoo call silently fails. I'm guessing the reason for this is because at run-time, the Users(0).Foo object is no longer of type User, but of a proxy class that inherits from User since the Friends list was lazy-loaded.

My question is this: shouldn't this generate a run-time exception? You get compile-time exceptions if you try to access another class's private properties, but when you run into a situation like this is looks like the app just ignores you and continues along its way.

Note: If I change the "private set" to a "protected set", everything works fine.

+1  A: 

As Paco points out only virtual methods/properties can be proxied, and C# does not allow virtual private members.

You could possibly access it via reflection, but my first thought would be that you should try to avoid it. Nonetheless, if you want to go there you need something along these lines:

// edit: fixed to use GetType
Type type = Friend[ 0 ].GetType().BaseType;
type.GetProperty("Foo",BindingFlags.Instance|BindingFlags.NonPublic).SetValue( Friends[0], 1, null );

Alternatively, you can use Fasterflect and do the same like this:

Friends[ 0 ].SetPropertyValue( "Foo", 1 );
Morten Mertner
I forgot to add the "virtual" keywords in front of my properties. Does this change things at all? It's still a public virtual property, but the setter is private.
Kevin Pang
As far as I know NHibernate uses Windsor to generate its proxies, so look at the docs for that to learn what exactly it supports. But why not just make the property setter protected instead of private? Reflection can be used to break your encapsulation anyway, so it would probably be a good idea to go for the pragmatic solution here.
Morten Mertner