hookeslaw
hookeslaw

Reputation: 155

Restricting scope of a class member beyond private

I was wondering if there was a way to scope access of a class member specifically to get/set implementations in c# to reduce the chance of me accidentally accessing them directly. Something like private but only allows get/set to access it, I was thinking that I could wrap each variable in their own class but that seems overkill for the restriction I'm looking for. Thanks

Upvotes: 3

Views: 564

Answers (4)

Steven Jeuris
Steven Jeuris

Reputation: 19130

If you don't need to do any operations in the accessors, use a auto-implemented property.

I'm guessing most likely you DO want to do operations and that's why you want to make sure you use the property instead of the backing field.

In that case consider the following:

  • Use a naming convention like "_instanceName" to indicate a private member field. (You should be doing this anyhow ...)
  • When you feel the operations inside your accessors are common, and reuseable, encapsulate it in a class. Don't worry about overkill until you run into performance issues.

I believe I might have found a possible workaround, and it is surprisingly small. This 'solution' might be a bit too clever however. Perhaps I'll do some benchmarking tests tomorrow. Problem is at the moment it is also scoped over every place it is used, perhaps by using generics this can be limited.

It makes use of the fact that lambdas always have the same backing method. By passing a lambda to a static constructor, a static object can keep track of this unique 'scope' and link variables to it. More details about this implementation can be found here.

Usage:

class LocalTestClass
{
    public int StaticTest( int setValue )
    {
        Local<int> test = Local<int>.Static( () => { } );
        int before = test.Value;
        test.Value = setValue;
        return before;
    }

    public int InstanceTest( int setValue )
    {
        Local<int> test = Local<int>.Instance( () => this );
        int before = test.Value;
        test.Value = setValue;
        return before;
    }
}

[TestMethod]
public void LocalStaticTest()
{
    LocalTestClass instance1 = new LocalTestClass();
    LocalTestClass instance2 = new LocalTestClass();

    instance1.StaticTest( 10 );
    Assert.AreEqual( 10, instance2.StaticTest( 20 ) );
    Assert.AreEqual( 20, instance1.StaticTest( 30 ) );
}

[TestMethod]
public void LocalInstanceTest()
{
    LocalTestClass instance1 = new LocalTestClass();
    LocalTestClass instance2 = new LocalTestClass();

    instance1.InstanceTest( 10 );
    Assert.AreEqual( 10, instance1.InstanceTest( 20 ) );
    instance2.InstanceTest( 50 );
    Assert.AreEqual( 20, instance1.InstanceTest( 30 ) );
}

The class:

public class Local<TValue>
{
    static readonly Dictionary<object, object> StaticScope
        = new Dictionary<object, object>();
    static readonly Dictionary<object, Dictionary<object, object>> InstanceScope
        = new Dictionary<object, Dictionary<object, object>>();


    public TValue Value { get; set; }


    private Local() { }


    public static Local<TValue> Static( Action scope )
    {
        if ( !StaticScope.ContainsKey( scope ) )
        {
            Local<TValue> newInstance = new Local<TValue>();
            StaticScope.Add( scope, newInstance );                
        }

        return StaticScope[ scope ] as Local<TValue>;
    }

    public static Local<TValue> Instance<TScope>( Func<TScope> scope )
    {
        object instance = scope();
        if ( !InstanceScope.ContainsKey( instance ) )
        {                
            InstanceScope.Add( instance, new Dictionary<object, object>() );

            if ( !InstanceScope[ instance ].ContainsKey( scope ) )
            {
                Local<TValue> newInstance = new Local<TValue>();
                InstanceScope[ instance ].Add( scope, newInstance );
            }
        }

        return InstanceScope[ instance ][ scope ] as Local<TValue>;
    }
}

A more general discussion about this topic can be found on Programmers.SE.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1503419

No, unfortunately not. I assume you'd be after something like this:

// Not actually valid C#!
public string Name
{
    // Only accessible within the property
    string name;

    get { return name; }
    set
    {
        if (value == null)
        {
            throw new ArgumentNullException();
        }
        name = value;
    }
}

I've wanted something like this before, too. Unfortunately it's not possible :(

Upvotes: 3

SLaks
SLaks

Reputation: 888177

You can add [Obsolete("Use the property")] to the field and suppress the warning in the property by writing #pragma warning disable 618.

Upvotes: 4

jason
jason

Reputation: 241779

This is not possible. The only access modifiers are private, internal, protected, protected internal and public and none fit the bill.

If you use an auto-property, however, then of course you can only access it by get and set.

Upvotes: 2

Related Questions