views:

336

answers:

3

Can I lock/unlock fields or objects at runtime against writing? In other words something like changing objects to read-only temporarily at runtime...

For example:

int x = 5; // x is 5  
LockObject(x);  
x = 7; // no change  
UnlockObject(x);  
x = 10; // x is 10

if not can you give me some possible solutions?

+1  A: 

Wrap it in a property and then use a boolean flag as the "lock".

You can also use a struct to handle this type of logic.

public struct LockableInt
{
    private int _value;
    public bool Locked;

    public void Lock(bool locked) {Locked = locked;}

    public int Value
    {
        get 
        { return _value; }
        set 
        { if (!Locked) _value = value; }
    }

    public override string ToString()
    {
        return _value.ToString();
    }
}

Sample client code:

public static void RunSnippet()
{
    LockableInt li = new LockableInt();
    li.Value = 5;
    Console.WriteLine(li.ToString());
    li.Lock(true);
    li.Value = 6;
    Console.WriteLine(li.ToString());
    li.Lock(false);
    li.Value = 7;
    Console.WriteLine(li.ToString());

}

Output:

5 5 7 Press any key to continue...

Paul Sasik
Mutable structs are almost always a **really** bad idea unless you know *exactly* what you are doing. And even then it is risky.
Marc Gravell
@Marc Gravell: I would go further and say "And even then it is a bad idea."
Jason
Would you mind expanding on that Marc, or providing a link to more info? i don't see much risk with my sample. What am i missing?
Paul Sasik
You have a method void M() { S s = whatever; Foo(); s.Mutate(); Bar(s); } You decide to refactor that as void Helper(S s){ Foo(); s.Mutate(); } void M() { S s = whatever; Helper(s); Bar(s); }. Now, FIND THE BUG you just introduced. Mutable value types make it VERY EASY to introduce bugs like this
Eric Lippert
What Eric said ;-p
Marc Gravell
+6  A: 

You can use accessors to do this...

public class X
{
    private bool locked = false;

    private int lockedVar;
    public int LockedVar
    {
        get { return lockedVar; }
        set { if (!locked) lockedVar = value; }
    }

    public void LockObject() { locked = true; }
    public void UnlockObject() { locked = false; }
}
Michael Bray
I know it differs from the question, but for the record I believe it would be better to throw an exception than to just drop the change.
Marc Gravell
@Marc: i was thinking the same thing but that would force the client code to handle exceptions as part of its logic which is typically frowned upon. You would still want an exception but to help the client avoid catching exceptions one could introduce an IsLocked read-only property that could be evaluated thus avoiding a throw when trying to change a locked value.
Paul Sasik
@Paul: Forcing client code to handle exceptions is frowned upon? By whom? Failing silently is something **I'd** certainly frown on, not to mention being forced to check some internal condition before assignment... Exceptions are your friends.
Pontus Gagge
@Pontus: You misinterpreted my comment. I was suggesting that it would not be a good idea to design an API with which the only way to discover if a property is locked is to throw/handle an exception. I suggested providing another property or getter method that would tell the client code whether the property is locked. Locking should not be thought of as an error condition and the handling of an exception should not be used as standard flow control.
Paul Sasik
@Paul: OK, that's more reasonable. Whether locking is an error or not depends at least in part on the problem domain (are lock conflicts a common occurence, or are we merely playing safe?).
Pontus Gagge
A: 

Thanks all for help. Here is a more generalized alternative.
I have decided that it would be more convenient to use freeze/unfreeze since lock/unlock exists in the context of multithreading programming.

public class FreezeableValue<T>  
{  
 private bool frozen;  
 private T value;

 public FreezeableValue()
 {
    frozen = false;
 }

 public FreezeableValue(T value)
 {
    this.value = value;
    frozen = false;
 }

 public void Freeze(bool frozen)
 {
    this.frozen = frozen;
 }

 public T Value
 {
    get { return value; }
    set
    {
        if (!frozen) this.value = value;
    }
 }
}
Heka