views:

145

answers:

8
+1  Q: 

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.

+1  A: 

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.

Jeff Sternal
A: 

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.

Craig Stuntz
+1  A: 

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.

Russ
+9  A: 

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!
}
}
statenjason
+1, Clean solution to the problem.
Kirk Woll
There are very good reasons to use interfaces rather than concrete types (and if `Person` has any behavior, I'd recommend this too) ... but how does this save any effort versus creating a class?
Jeff Sternal
I like this too, but wouldn't it be easy for them to just cast it back into a Person class? `Person iCanChangeProperties = (Person)SomeClass.Manager;` And the Cast doesn't protect against them using that reference to make changes to the properties... I might just have to stick to clone. Though, the ReadOnly interface would be nice so reflection tells them that they **CAN NOT** do setter properties.
myermian
@myermian, You're correct. Although it would be a poor practice on the user's part to cast it. Making Person internal could stop that (but would prevent them from constructing new ones). Even marked internal, using reflection, they could get access to the setters. Also, passing back a clone wouldn't prevent a user from reflecting on SomeClass and getting *_manager* directly. You can't prevent people from shooting themselves in the foot. At the point someone starts going against your exposed API, they deserve whatever consequences come from it.
statenjason
@jeff I believe the benefit could come from the maintaining Person. If the IPerson interface changes, the Compiler will enforce that Person is updated to match it. Also, if a ReadOnlyPerson class was used, some sort of mapping of Person->ReadOnlyPerson would need to be created.
statenjason
@statenjason, I guess you're right. You can only go so far to protect the user from "shooting themselves in the foot".
myermian
+1  A: 

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

jethro
+1  A: 

You can transform the Person class into an immutable object.

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

    public String FirstName { get; private set; } 
    public String LastName { get; priavte set; } 
} 
Jerod Houghtelling
A: 

There is no mechanism by which an existing type can be made read-only.

What situation are you facing that you need a read-only version of an existing type?

Bryan Watts
A: 

anonymous objects are read-only

Omu