我正在尝试创建一个接口,该接口返回实现它的实例的修改后的副本,并且不修改原始实例。
public interface ICensoreable<T> {
T GetCensored();
}
Run Code Online (Sandbox Code Playgroud)
和实现的对象
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;
}
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以在 GetCensored不会修改User(或T)实例的接口上强制执行?
随着最近发布的 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();
}
Run Code Online (Sandbox Code Playgroud)
使用GetCensored()
方法:
var user = new User();
var censored = ((ICensoreable<User>)user).GetCensored();
Run Code Online (Sandbox Code Playgroud)
注意:截至撰写本文时,此实现将此问题在 VS 16.5.4 及以后版本中得到修复,并且代码可以正确运行。NullReferenceException
在方法的第一行抛出 a 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 问题一起存在了几周。根据某人的说法,在后续修复后,此问题已在 16.5.0 Preview 1.0 中修复。
编辑2:目前在VS 16.5.0 Preview 1.0,异常仍然是相同的;目前尚未发布针对此问题的修复方案。
最终编辑:从 VS 16.5.4 开始(我希望),这段代码工作得很好。没有抛出异常。