25

有没有办法返回一个对象的只读实例?

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!
    }
}

是通过返回 Clone() 来做到这一点的唯一方法,以便对 Clone 而不是对原始版本进行任何更改?我知道对于数组,有一个函数可以将数组作为只读返回。哦,我知道这是一个引用类型......我还想知道是否有一些隐藏的 C# 功能来锁定写作部分。

我试图想出一个通用的只读包装类,但无法弄清楚如何在不做一些昂贵的反射等的情况下将属性设为只读。

哦,我真的想避免创建所有只读属性的类的第二个版本。到时候,我还不如归还克隆人。

4

8 回答 8

40

为了避免创建额外的类,您可以将其实现为仅具有只读属性的接口 IPerson。

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!
}
}
于 2010-08-23T18:04:45.573 回答
7

您可以将 Person 类转换为不可变对象,如下所示。

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; } 

} 
于 2010-08-23T18:28:04.630 回答
4

在某些条件下,您可以在Castle.DynamicProxy. 阅读这篇博了解详情。

于 2010-08-23T18:25:18.317 回答
2

没有这样的功能 - 你已经涵盖了你的选择。

要么克隆它,要么创建一个只读Person类型。通常首选后一种方法,因为语义更清晰:调用者很明显他们不应该(也不能)修改实例。

于 2010-08-23T17:46:12.947 回答
2

这是另一个示例,基于 List.AsReadOnly 在 .NET Framework 2.0 中的实现方式。在适当的方法中使用布尔值 (IsReadOnly) 来防止更新:

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;
        }
    }
}

测试它:

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
}
于 2012-02-26T20:00:12.370 回答
1

没有办法使对象的所有属性在类外部只读。在上面的示例中,您不能将 _manager 属性设置为只读,除非您将 Person 类中的属性更改为只读。

您可以将 Person 类的属性设置器设置为内部,这意味着只有与 Person 相同的程序集中的类才能更改属性。

或者,如果您将属性的设置器设为私有,则只有 Person 中的代码才能更改属性的值。

于 2010-08-23T17:47:13.060 回答
0

不。您正在寻找类似 C++ 风格的东西const,并且由于各种 原因C# 没有。

然而,匿名类型是真正不可变的。

于 2010-08-23T17:46:44.723 回答
0

匿名对象是只读的。

于 2010-08-23T20:42:55.387 回答