tags:

views:

174

answers:

4

I need a field that can be assigned to from where ever I want, but it should be possible to assign it only once (so subsequent assignments should be ignored). How can I do this?

+14  A: 

That would not be a readonly field then. Your only options for initializing real readonly fields are field initializer and constructor.

You could however implement a kind of readonly functionality using properties. Make your field as properties. Implement a "freeze instance" method that flipped a flag stating that no more updates to the readonly parts are allowed. Have your setters check this flag.

Keep in mind that you're giving up a compile time check for a runtime check. The compiler will tell you if you try to assign a value to a readonly field from anywhere but the declaration/constructor. With the code below you'll get an exception (or you could ignore the update - neither of which are optimal IMO).

EDIT: to avoid repeating the check you can encapsulate the readonly feature in a class.

Revised implementation could look something like this:

class ReadOnlyField<T> {
    public T Value {
        get { return _Value; }
        set { 
            if (Frozen) throw new InvalidOperationException();
            _Value = value;
        }
    }
    private T _Value;

    private bool Frozen;

    public void Freeze() {
        Frozen = true;
    }
}


class Foo {
    public readonly ReadOnlyField<int> FakeReadOnly = new ReadOnlyField<int>();

    // forward to allow freeze of multiple fields
    public void Freeze() {
        FakeReadOnly.Freeze();
    }
}

Then your code can do something like

        var f = new Foo();

        f.FakeReadOnly.Value = 42;

        f.Freeze();

        f.FakeReadOnly.Value = 1337;

The last statement will throw an exception.

Brian Rasmussen
I'm currently using such a "freeze instance" solution but my class has so many fields and it makes no sense to add 5 line for each field. But what about "field initializer"? I don't know what is it. Is a it possible to assign to read only fields there? Is this as same as "Properties"?
afsharm
No field initializer will not help you here. There are no way you can do what you're asking with a regular readonly field.
Brian Rasmussen
@afsharm - If it's not worth adding 5 lines for each field then you obviously don't need this functionality (not really sure why u would anyway).
Stevo3000
plz consider comments under question itself and all answers.
afsharm
A: 

Or maybe you mean a field that everyone can read but only the class itself can write to? In that case, use a private field with a public getter and a private setter.

private TYPE field;

public TYPE Field
{
   get { return field; }
   private set { field = value; }
}

or use an automatic property:

public TYPE Field { get; private set; }
Eric Minkes
No! I don't mean so! Indeed I have an object that is populated by NHibernate from database and then is passed to UI. User may edit some fields or not but I'm supposed to not allows changes in some specific fields. On of the ways that I think I can achieve to this is to define a shadow field for each of fields as READ ONLY and then compare this shadow fields with original ones and realize if changes has been happened. Please consider thoese fields are not populated in constructor.
afsharm
Would it not be better to make it so the user can only edit some of them, making read only fields shown in labels rather than text boxes, or some such? If you are using the property grid you can stick the [ReadOnly] attribute above it.
Courtney de Lautour
It's SOA application. We have UI in web, winform and console and I'm not allowed to do this anywhere outside of SERVICE.
afsharm
+1  A: 

Try the following:

class MyClass{
private int num1;

public int Num1
{
   get { return num1; }

}


public MyClass()
{
num1=10;
}

}
Himadri
A: 

in Java and perhaps in any other languages (please correct me if i'm wrong), you can do that by declaring a variable/field as STATIC (can be access anywhere as long as it's public) and FINAL (value can not be changed during run-time once assigned). :)

ultrajohn