我正在尝试创建一个接口,该接口返回实现该实例的修改后的副本,而不修改原始实例。
public interface ICensoreable<T> {
T GetCensored();
}
以及实现的对象
public class User:ICensoreable<User> {
public User(User copyFrom) {
this.name = copyFrom.name;
this.password = copyFrom.password;
}
public string name;
public string password;
public User GetCensored() {
User result = new User(this);
result.password = null;
return result;
}
}
有什么方法可以强制在接口上 GetCensored不会修改用户(或T)实例吗?
答案 0 :(得分:3)
使用最新版本的C#8.0,您现在可以在界面中定义默认方法实现。因此,您可以强制默认使用GetCensored()
方法不修改原始实例。通过将默认实现标记为sealed
,禁止实现该接口的类型显式重新实现该方法。由于该方法仅在接口中实现,因此您需要在调用ICensoreable<T>
方法之前将对象强制转换为GetCensored()
。
这是我使用的实现:
public interface ICensoreable<T>
{
sealed ICensoreable<T> GetCensored()
{
var result = Clone();
result.CensorInformation();
return result;
}
ICensoreable<T> Clone();
void CensorInformation();
}
public class User : ICensoreable<User>
{
public User(User other)
{
name = other.name;
password = other.password;
}
public string name;
public string password;
public void CensorInformation()
{
password = null;
}
public User Clone() => new User(this);
ICensoreable<User> ICensoreable<User>.Clone() => Clone();
}
使用GetCensored()
方法:
var user = new User();
var censored = ((ICensoreable<User>)user).GetCensored();
注意::在撰写本文时,此实现将在NullReferenceException
方法的第一行中抛出GetCensored()
(使用VS 16.4.0 Preview 2.0上的C#8.0)。我个人认为这是一个错误,因为删除sealed
关键字不会对完全相同的代码造成任何问题。此外,我尝试了另一种实现,其中涉及初始化一个类型为T
的新对象,该对象也崩溃了。该行是var result = new T();
,它抛出了NullReferenceException
。
理论上,按照建议,sealed
关键字只是防止类型覆盖接口方法,而仅保留默认实现。
编辑1:当前在VS 16.4.0 Preview 5.0中,引发的异常是AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
。经过一番调查后,我意识到与相关的GitHub issue一起已知的bug已经有几个星期了。根据某人的说法,在后续fix之后,此问题已在16.5.0 Preview 1.0及更高版本中修复。
编辑2:当前在VS 16.5.0 Preview 1.0中,例外仍然是相同的。还没有针对此问题的修复程序。