有没有办法返回对象的只读实例?
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!
}
}
唯一的方法是通过返回克隆()来执行此操作,以便对克隆而不是原始文件进行任何更改?我知道对于Arrays,有一个函数可以将Array作为只读方式返回。哦,我知道这是一个参考类型...我还想知道是否有一些隐藏的C#功能来锁定写入部分。
我试图想出一个Generic ReadOnly包装器类,但是如果没有做一些昂贵的反射就不知道如何将这些属性作为readonly来实现。
哦,我真的试图避免创建所有只读属性的类的第二个版本。那时,我不妨返回克隆。
答案 0 :(得分:38)
为了避免创建额外的类,您可以将其实现为只具有只读属性的接口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!
}
}
答案 1 :(得分:6)
您可以将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; }
}
答案 2 :(得分:4)
在Castle.DynamicProxy
的帮助下,你可以在某些条件下冻结对象(使其成为不可变的)。请阅读此博客post了解详情。
答案 3 :(得分:2)
没有这样的功能 - 你已经涵盖了你的选择。
克隆它或制作只读Person
类型。后一种方法通常是首选的,因为语义更清晰:调用者很明显他们不应该(也不能)修改实例。
答案 4 :(得分:2)
这是另一个例子,基于如何在.NET Framework 2.0中实现List.AsReadOnly。在适当的方法中使用布尔值(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
}
答案 5 :(得分:1)
没有办法从类中外部读取对象的所有属性。在上面的示例中,除非将Person类中的属性更改为只读,否则不能将_manager属性设置为只读。
您可以将Person类的属性的setter设置为internal,这意味着只有与Person相同的程序集中的类才能更改属性。
或者,如果您将属性的setter设为private,则只有Person中的代码才能更改属性的值。
答案 6 :(得分:0)
答案 7 :(得分:0)
匿名对象是只读的。