是否可以在不强制转换的情况下在 C# 中实现 "virtual constructor" 模式?
Is it possible to implement the "virtual constructor" pattern in C# without casts?
我正在编写一个编写 C# 的程序,该程序最终会被编译到应用程序中。我希望每个生成的类型都提供一个 "deep clone" 函数来复制整个数据树。也就是说,我希望有人能够做到:
var x = new Base(); // Base has public virtual Base DeepClone() { ... }
var y = new Derived(); // Derived overrides DeepClone
Base a = x.DeepClone();
Base b = y.DeepClone();
// Derived c = x.DeepClone(); // Should not compile
Derived d = y.DeepClone(); // Does not compile, DeepClone returns Base
而不是
var x = new Base();
var y = new Derived();
Base a = x.DeepClone();
Base b = y.DeepClone();
// Derived c = x.DeepClone(); // Should not compile
Derived d = (Derived)y.DeepClone();
但是,C# 不允许您在简单的覆盖中执行此操作;覆盖必须 return 与基础上声明的类型相同。
由于我编写的代码无论如何都会消除样板文件,所以我可以生成一些东西来允许第一个块进行编译吗?我尝试了类似于以下内容的操作:
abstract class Base
{
public abstract Base DeepClone();
}
class Base2 : Base
{
int Member { get; set; }
public Base2() { /* empty on purpose */ }
public Base2(Base2 other)
{
this.Member = other.Member;
}
public override Base2 DeepClone()
{
return new Base2(this);
}
}
sealed class Derived : Base2
{
string Member2 { get; set; }
public Derived() { /* empty on purpose */ }
public Derived(Derived other)
: base(other)
{
this.Member2 = other.Member2;
}
public override Derived DeepClone()
{
return new Derived(this);
}
}
但这不会编译,因为覆盖不匹配。我还尝试从基础覆盖该方法并使用 "new" 关键字隐藏它,但这也不起作用。
是的,它是可行的,但您必须将抽象方法从 public 转移到受保护,然后创建一个 public 非抽象函数来调用受保护的方法。派生的 类 只需要实现受保护的函数并且可以隐藏 public 函数,执行本应由客户端执行的转换。
abstract class Base
{
public Base DeepClone()
{
return CloneInternal();
}
protected abstract Base CloneInternal();
}
class Base2 : Base
{
int Member { get; set; }
public Base2() { /* empty on purpose */ }
public Base2(Base2 other)
{
this.Member = other.Member;
}
new public Base2 DeepClone()
{
return (Base2)CloneInternal();
}
protected override Base CloneInternal()
{
return new Base2(this);
}
}
sealed class Derived : Base2
{
string Member2 { get; set; }
public Derived() { /* empty on purpose */ }
public Derived(Derived other)
: base(other)
{
this.Member2 = other.Member2;
}
new public Derived DeepClone()
{
return (Derived)CloneInternal();
}
protected override Base CloneInternal()
{
return new Derived(this);
}
}
这是一种不涉及任何转换的方法。它不允许你从你的第一个片段中做 new Base()
,这没有任何意义,因为它是抽象的,但其余的工作:
interface Base
{
Base DeepClone();
}
abstract class Base<T>: Base where T: Base<T>
{
public abstract T DeepClone();
Base Base.DeepClone() {
return DeepClone();
}
}
class Base2 : Base<Base2>
{
public override Base2 DeepClone()
{
return new Base2();
}
}
然后,在您的 Main
方法中:
public static void Main()
{
var y = new Base2(); // Base2 overrides DeepClone
Base b = y.DeepClone();
Base2 c = y.DeepClone(); // Compiles an works
}
我正在编写一个编写 C# 的程序,该程序最终会被编译到应用程序中。我希望每个生成的类型都提供一个 "deep clone" 函数来复制整个数据树。也就是说,我希望有人能够做到:
var x = new Base(); // Base has public virtual Base DeepClone() { ... }
var y = new Derived(); // Derived overrides DeepClone
Base a = x.DeepClone();
Base b = y.DeepClone();
// Derived c = x.DeepClone(); // Should not compile
Derived d = y.DeepClone(); // Does not compile, DeepClone returns Base
而不是
var x = new Base();
var y = new Derived();
Base a = x.DeepClone();
Base b = y.DeepClone();
// Derived c = x.DeepClone(); // Should not compile
Derived d = (Derived)y.DeepClone();
但是,C# 不允许您在简单的覆盖中执行此操作;覆盖必须 return 与基础上声明的类型相同。
由于我编写的代码无论如何都会消除样板文件,所以我可以生成一些东西来允许第一个块进行编译吗?我尝试了类似于以下内容的操作:
abstract class Base
{
public abstract Base DeepClone();
}
class Base2 : Base
{
int Member { get; set; }
public Base2() { /* empty on purpose */ }
public Base2(Base2 other)
{
this.Member = other.Member;
}
public override Base2 DeepClone()
{
return new Base2(this);
}
}
sealed class Derived : Base2
{
string Member2 { get; set; }
public Derived() { /* empty on purpose */ }
public Derived(Derived other)
: base(other)
{
this.Member2 = other.Member2;
}
public override Derived DeepClone()
{
return new Derived(this);
}
}
但这不会编译,因为覆盖不匹配。我还尝试从基础覆盖该方法并使用 "new" 关键字隐藏它,但这也不起作用。
是的,它是可行的,但您必须将抽象方法从 public 转移到受保护,然后创建一个 public 非抽象函数来调用受保护的方法。派生的 类 只需要实现受保护的函数并且可以隐藏 public 函数,执行本应由客户端执行的转换。
abstract class Base
{
public Base DeepClone()
{
return CloneInternal();
}
protected abstract Base CloneInternal();
}
class Base2 : Base
{
int Member { get; set; }
public Base2() { /* empty on purpose */ }
public Base2(Base2 other)
{
this.Member = other.Member;
}
new public Base2 DeepClone()
{
return (Base2)CloneInternal();
}
protected override Base CloneInternal()
{
return new Base2(this);
}
}
sealed class Derived : Base2
{
string Member2 { get; set; }
public Derived() { /* empty on purpose */ }
public Derived(Derived other)
: base(other)
{
this.Member2 = other.Member2;
}
new public Derived DeepClone()
{
return (Derived)CloneInternal();
}
protected override Base CloneInternal()
{
return new Derived(this);
}
}
这是一种不涉及任何转换的方法。它不允许你从你的第一个片段中做 new Base()
,这没有任何意义,因为它是抽象的,但其余的工作:
interface Base
{
Base DeepClone();
}
abstract class Base<T>: Base where T: Base<T>
{
public abstract T DeepClone();
Base Base.DeepClone() {
return DeepClone();
}
}
class Base2 : Base<Base2>
{
public override Base2 DeepClone()
{
return new Base2();
}
}
然后,在您的 Main
方法中:
public static void Main()
{
var y = new Base2(); // Base2 overrides DeepClone
Base b = y.DeepClone();
Base2 c = y.DeepClone(); // Compiles an works
}