简体   繁体   中英

c# readonly object

Is there any way to return a readonly instance of an object?

public class Person
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

public class SomeClass
{
    public SomeClass(Person manager)
    {
        if (manager == null)
            throw new ArgumentNullException("manager");

        _manager = manager;
    }

    private readonly Person _manager;
    public Person Manager
    {
        get { return _manager; } //How do I make it readonly period!
    }
}

Is the only way to do this by returning a Clone() so that any changes are done to the Clone and not the original? I know for Arrays there is a function to return the Array as read-only. Oh, and I know this is a reference type... I'm moreover wondering if there's some hidden C# feature to lock the writing portion.

I was trying to come up with a Generic ReadOnly wrapper class, but couldn't figure out how to get the properties as readonly without doing some expensive reflection and the such.

Oh, and I'm really trying to avoid creating a second version of the class that is all readonly properties. At that point, I might as well return the clone.

To save yourself from creating an extra class, you could make it implement it as an interface IPerson that only has read only properties.

public interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}
public class Person:IPerson
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

public class SomeClass
{
public SomeClass(Person manager)
{
    if (manager == null)
        throw new ArgumentNullException("manager");

    _manager = manager;
}

private readonly Person _manager;
public IPerson Manager
{
    get { return _manager; } //How do I make it readonly period!
}
}

You can transform the Person class into an immutable object, as below..

public class Person 
{ 
    public Person( string firstName, string lastName )
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public String FirstName { get; private set; } 
    public String LastName { get; private set; } 

} 

You can freeze object (make it immutable) under some conditions with help of Castle.DynamicProxy . Read this blog post for details.

There is no such feature - you've covered your options.

Either clone it or make a read-only Person type. The latter approach is usually preferred because the semantics are clearer: it's obvious to callers that they shouldn't (and can't) modify the instance.

Here an other example, based on how List.AsReadOnly is implemented in the .NET Framework 2.0. A boolean (IsReadOnly) is used in appropriate methods to prevent updates:

public class Person
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (!IsReadOnly) _firstName = value;
            else throw new AccessViolationException("Object is read-only.");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (!IsReadOnly) _lastName = value;
            else throw new AccessViolationException("Object is read-only.");
        }
    }

    internal virtual bool IsReadOnly { get { return false; } }

    public ReadOnlyPerson AsReadOnly()
    {
        return new ReadOnlyPerson(this);
    }

    public class ReadOnlyPerson : Person
    {
        private Person _person;
        internal override bool IsReadOnly { get { return true; } }

        internal ReadOnlyPerson(Person person) // Contructor
        {
            this._person = person;
        }
    }
}

To test it :

static void Main(string[] args)
{
    Person p1 = new Person();
    p1.FirstName = "Joe";
    p1.LastName = "Bloe";
    Console.WriteLine("First = {0} Last = {1}", p.FirstName, p.LastName);

    var p2 = p1.AsReadOnly();
    p2.FirstName = "Josephine"; // AccessViolationException
}

There is not a way to make all the properties of your object readonly externally from the class. In your example above, you cannot make the _manager properties readonly, unless you changed the properties within the Person class to be readonly.

You can make the setter of properties of the Person class internal, meaning that only classes within the same assembly as Person can change the properties.

Or, if you make the setter of the properties private, then only code within Person can change the values of the properties.

No. You're looking for something like C++-style const -ness, and for various reasons C# doesn't have that.

However, anonymous types are truly immutable.

匿名对象是只读的。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM