Return 来自父 class 方法的子 class 类型
Return type of child class from parent class method
如果我有 class A
和 class 继承自 [=] 的 B
、C
和 D
13=],有没有办法在 A
中编写一个方法,当在 subclass 上调用时,将具有 subclass 的 return 类型?
所以如果我要执行 A.myMethod()
,我会得到一个 A
,如果我要执行 B.myMethod()
,我会得到一个 B
的实例?
假设你只想在A
中声明方法myMethod
,你可以这样做:
namespace Test
{
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
Console.WriteLine(a.M());
Console.WriteLine(b.M());
}
}
class A
{
public A M()
{
return (A)Activator.CreateInstance(GetType());
}
}
class B : A
{
}
}
打印:
Test.A
Test.B
你说的是基本上一个工厂method/pattern。有点不对劲,因为创建自己的实例很奇怪。
但是当然,你可以这样写:
class A
{
public virtual A Create()
{
return new A();
}
}
class B
{
public override A Create()
{
return new B();
}
}
当然,return 类型必须保留为基础 class,但由于您正在利用多态性,这应该不是问题。
通常情况下,工厂方法会在 另一个 专门构建的 class 中,如你所知。
是和否。考虑:
public class Parent
{
public int MyProperty { get; set; }
public virtual Parent MyMethod()
{
return new Parent();
}
}
public class A : Parent
{
public override Parent MyMethod()
{
return new A();
}
}
在 A 中,虽然 return 类型是 Parent,但您 return 是一个 A。
如果你询问编译时间,不,你不能用不同的 return 类型编写重写方法。
但是在 运行 时间是的,你可以并且你将拥有那些类型的实例,但是你必须编写代码以获得 return 类型的 'A' 然后将它们转换为想要的类型。
你问的不是严格的多态性,因为你想覆盖 return 类型,因此具有与原始方法不同的签名。真正的多态性改变了这个签名的 none,所以你问的不是 C# 中的第一个 class 情况。
话虽如此,至少有两种方法。
最简单的方法是覆盖方法,使用new
关键字隐藏原来的方法,让你改变签名。
public new B MyMethod() { return (B)(base.MyMethod()); }
这将允许 B
到 return 和 B
的任何用法,但实际上不会覆盖 A.MyMethod
的行为。避免在代码中重复类型转换很有用。
如果您还需要重写该方法以允许它 return 类型为 B
的对象,这不能共存于同一个 class,因为编译器认为相同签名(相同的名称,相同的参数,即使 return 类型明显不同)。
第二种方法称为静态多态性,如果您使用某种工厂,它会非常有用,但变通起来可能非常棘手,因为它允许一级实际继承。静态多态类型以具有针对自身约束的通用组件的类型开始:
public class A<TSelf> where TSelf : A<TSelf> { }
public class B : A<B> { }
这意味着您的方法可以 return 类型为 TSelf
的对象,甚至可以将其设为抽象方法,因此每个继承者都必须处理构造函数,但是任何 class 继承自B
更难覆盖它,因为它继承自 A<B>
,而不是 A<C>
如果我有 class A
和 class 继承自 [=] 的 B
、C
和 D
13=],有没有办法在 A
中编写一个方法,当在 subclass 上调用时,将具有 subclass 的 return 类型?
所以如果我要执行 A.myMethod()
,我会得到一个 A
,如果我要执行 B.myMethod()
,我会得到一个 B
的实例?
假设你只想在A
中声明方法myMethod
,你可以这样做:
namespace Test
{
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
Console.WriteLine(a.M());
Console.WriteLine(b.M());
}
}
class A
{
public A M()
{
return (A)Activator.CreateInstance(GetType());
}
}
class B : A
{
}
}
打印:
Test.A
Test.B
你说的是基本上一个工厂method/pattern。有点不对劲,因为创建自己的实例很奇怪。
但是当然,你可以这样写:
class A
{
public virtual A Create()
{
return new A();
}
}
class B
{
public override A Create()
{
return new B();
}
}
当然,return 类型必须保留为基础 class,但由于您正在利用多态性,这应该不是问题。
通常情况下,工厂方法会在 另一个 专门构建的 class 中,如你所知。
是和否。考虑:
public class Parent
{
public int MyProperty { get; set; }
public virtual Parent MyMethod()
{
return new Parent();
}
}
public class A : Parent
{
public override Parent MyMethod()
{
return new A();
}
}
在 A 中,虽然 return 类型是 Parent,但您 return 是一个 A。
如果你询问编译时间,不,你不能用不同的 return 类型编写重写方法。
但是在 运行 时间是的,你可以并且你将拥有那些类型的实例,但是你必须编写代码以获得 return 类型的 'A' 然后将它们转换为想要的类型。
你问的不是严格的多态性,因为你想覆盖 return 类型,因此具有与原始方法不同的签名。真正的多态性改变了这个签名的 none,所以你问的不是 C# 中的第一个 class 情况。
话虽如此,至少有两种方法。
最简单的方法是覆盖方法,使用new
关键字隐藏原来的方法,让你改变签名。
public new B MyMethod() { return (B)(base.MyMethod()); }
这将允许 B
到 return 和 B
的任何用法,但实际上不会覆盖 A.MyMethod
的行为。避免在代码中重复类型转换很有用。
如果您还需要重写该方法以允许它 return 类型为 B
的对象,这不能共存于同一个 class,因为编译器认为相同签名(相同的名称,相同的参数,即使 return 类型明显不同)。
第二种方法称为静态多态性,如果您使用某种工厂,它会非常有用,但变通起来可能非常棘手,因为它允许一级实际继承。静态多态类型以具有针对自身约束的通用组件的类型开始:
public class A<TSelf> where TSelf : A<TSelf> { }
public class B : A<B> { }
这意味着您的方法可以 return 类型为 TSelf
的对象,甚至可以将其设为抽象方法,因此每个继承者都必须处理构造函数,但是任何 class 继承自B
更难覆盖它,因为它继承自 A<B>
,而不是 A<C>