Edw*_*vey 6 c# class instance named
对于某些类,理想情况下,我想创建特殊的命名实例,类似于"null".据我所知,这是不可能的,所以相反,我使用静态构造函数创建类的静态实例,类似于:
public class Person
{
public static Person Waldo; // a special well-known instance of Person
public string name;
static Person() // static constructor
{
Waldo = new Person("Waldo");
}
public Person(string name)
{
this.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,Person.Waldo是Person类的一个特殊实例,我创建它是因为在我的程序中,有很多其他类可能想要引用这个特殊的着名实例.
实现这种方式的缺点是我不知道如何使Person.Waldo的所有属性都是不可变的,而"普通"Person实例的所有属性都应该是可变的.每当我不小心有一个Person对象指向Waldo时,我不小心不检查它是否指的是Waldo,那么我不小心破坏了Waldo的属性.
是否有更好的方法,甚至是一些其他替代方法来定义类的特殊知名实例?
我现在知道的唯一解决方案是实现get和set访问器,并检查每个集合上的"if(this == Waldo)throw new ...".虽然这有效,但我认为C#可以比我实现它做得更好.如果只有我能找到一些C#方式来使得Waldo的所有属性只读(除了在静态构造函数中).
在继承Person的Person内部创建一个私有类ImmutablePerson : Person。
锁定所有属性设置器:例如,使用NotImplementedException覆盖它们。
您的静态Person初始化变为:
public static readonly Person Waldo = new ImmutablePerson("Waldo");
并且静态构造函数也可能被删除。
感谢您的所有建议 - 这是解决方案。我需要将字符串设为虚拟,重写公共派生类中的访问器,并使用 bool 标志来允许修改。
需要注意的是,“name”是一个引用类型,尽管我已经阻止更改“name”所指的内容,但如果它不是字符串,例如包含自修改方法的类,它尽管已经阻止了对对象引用的修改,但仍然可以修改对象的内容。
class Program
{
static void Main(string[] args)
{
Person myPerson = new Person("Wenda");
System.Console.WriteLine("myPerson is " + myPerson.name); // Prints "myPerson is Wenda"
if (myPerson == Person.Waldo)
System.Console.WriteLine("Found Waldo (first attempt)"); // doesn't happen
else
System.Console.WriteLine("Still trying to find Waldo..."); // Prints "Still trying to find Waldo..."
myPerson.name = "Bozo";
System.Console.WriteLine("myPerson is now " + myPerson.name); // Prints "myPerson is now Bozo"
myPerson = Person.Waldo;
if (myPerson == Person.Waldo)
System.Console.WriteLine("Found Waldo (second attempt)"); // Prints "Found Waldo (second attempt)"
System.Console.WriteLine("myPerson is " + myPerson.name); // Prints "myPerson is Waldo"
System.Console.WriteLine("Now changing to The Joker..."); // Prints "Now changing to The Joker"
try
{
myPerson.name = "The Joker"; // throws ImmutablePersonModificationAttemptException
}
catch (ImmutablePersonModificationAttemptException)
{
System.Console.WriteLine("Failed to change"); // Prints "Failed to change"
}
System.Console.WriteLine("myPerson is now " + myPerson.name); // Prints "myPerson is now Waldo"
Thread.Sleep(int.MaxValue); // keep the console alive long enough for me to see the result.
}
}
public class Person
{
public static readonly ImmutablePerson Waldo = new ImmutablePerson("Waldo");
public virtual string name { get; set; }
public Person() // empty base constructor required by ImmutablePerson(string) constructor
{ }
public Person(string name)
{
this.name = name;
}
}
public class ImmutablePersonModificationAttemptException : Exception
{ }
public class ImmutablePerson : Person
{
private bool allowMutation;
protected string _name;
public override string name
{
get
{
return _name;
}
set
{
if (allowMutation)
_name = value;
else
throw new ImmutablePersonModificationAttemptException();
}
}
public ImmutablePerson(string name)
: base()
{
allowMutation = true;
this.name = name;
allowMutation = false;
}
}
Run Code Online (Sandbox Code Playgroud)