c#面向对象返回类型this;呼叫孩子
本文关键字:呼叫 孩子 this 面向对象 返回类型 | 更新日期: 2023-09-27 18:12:49
我有两个类,每个类在所有函数中返回自己:
public class Parent{
public Parent SetId(string id){
...
return this
}
}
public class Child : Parent{
public Child SetName(string id){
...
return this
}
}
我想启用这种API:
new Child().SetId("id").SetName("name");
不能访问SetName
,因为SetId
返回Parent
, SetName
在Child
上。
如何?
如果您真的想要这种流畅的行为,并且Parent
类可以抽象,那么您可以这样实现:
public abstract class Parent<T> where T : Parent<T>
{
public T SetId(string id) {
return (T)this;
}
}
public class Child : Parent<Child>
{
public Child SetName(string id) {
return this;
}
}
现在可以这样写:
new Child().SetId("id").SetName("name");
我可能在这里错过了重点,但看起来你真的只是试图设置属性。如果您将它们作为属性公开,则可以使用对象初始化器调用。
var child = new Child()
{
Id = value1;
Name = value2;
}
你也可以调用一个方法,而不是在初始化式中设置一个值。
我觉得很奇怪,您想从当前实例中返回对类的当前实例的引用。为了访问对象的属性和方法,您是否已经有了这样一个引用?你可能在考虑克隆吗?
除非我错过了关于你的模型的一些东西,似乎一个适当的初始化方案,一些无聊的属性定义,也许一个工厂类可能更像你正在寻找的。似乎您还可以考虑将带有ID的Parent设置为不可变属性,尽管您的需求可能会为这样做创建一个真正的理由。
下面是一些可能有用的类定义。现在圣路易斯还早,我还没有完全喝醉,所以我可能错过了什么…: -)父:
public class Parent
{
protected string _id;
// Protected default constructor so tht this class can be inherited:
protected Parent() { }
// REquired to set ID at initialization;
public Parent(String ID)
{
_id = ID;
}
// Read-only:
public String ID
{
get { return _id; }
}
// This seems a little dodgy. Why would you want to return a reference
// to the current instance as a result of resetting the ID?
public Parent SetID(String ID)
{
_id = ID;
return this;
}
}
父工厂:
public class ParentFactory
{
public static Parent NewParent(String ID)
{
Parent newParent = new Parent(ID);
return newParent;
}
}
孩子:
public class Child : Parent
{
private string _name;
// Protected default constructor so tht this class can be inherited:
protected Child() { }
// Initialize a new Child with the ID property required for the parent:
public Child(String ID)
{
base.SetID(ID);
}
// Initialize a new child with both properties set:
public Child(String ID, String Name) : this(ID)
{
_name = Name;
}
// This could be read-only as well:
public String Name
{
get { return _name; }
set { _name = value; }
}
// Again, seems kinda dodgy:
public Child SetName(String name)
{
return this;
}
}
A Child Factory:
public class ChildFactory
{
public static Child NewChild(String ID)
{
Child newChild = new Child(ID);
return newChild;
}
public static Child NewChild(String ID, String Name)
{
Child newChild = new Child(ID, Name);
return newChild;
}
}
Davide Piras是对的,一种方法是使用虚方法,或者更好的是使用接口。
查看此代码
public interface INode
{
INode SetName(string aName);
INode SetId(string aId);
}
public class Parent : INode
{
public virtual INode SetId(string id)
{
...
return this
}
public virtual INode SetName(string aId)
{
return this;
}
}
public class Child : Parent
{
public override INode SetName(string id)
{
...
return this;
}
}
看起来您正在尝试创建一个流畅的界面。您确定这将是开发人员使用这些类的最简单方法吗?
如何使用简单的旧属性'Name'和'Id'?这很好且易于使用,特别是在使用集合初始化器语法时。
我在这里发现了一个类似的问题,但是对于java语言:如何使java父类方法返回子类的对象
试图编译它,但不工作,看到我的剪辑和看到我的评论,基本上看起来像在Java中,我们可以将其转换为T,但在c#现在。有趣的…
(这不是你问题的解决方案,我只是报告我试图做什么,我能走多远,如果有人知道一些魔法让这个工作保持这样的设计…)欢迎:))
class Program
{
static void Main(string[] args)
{
var obj = new Child().SetId("id").SetName("aaa");
}
}
public class Parent<T>
{
public virtual T SetId(string id)
{
// this does not work
return (T)this;
// this compiles but is NOT what we want :(
//return default(T);
}
}
public class Child : Parent<Child>
{
public Child SetName(string name)
{
return this;
}
}
这是怎么回事:((孩子)(新的子().SetId (" id ")) .SetName("名字");
这里的解释是,虽然对象的运行时类型是Child,但是c#在编译你想要支持的表达式时使用的静态类型推断是SetId("id")的静态类型是Parent。因为SetId是在Parent类中定义的。
实际上你的对象是Child类型的,并且有一个SetName方法。因此,SetName对你是可用的,但只有当你告诉c#把对象当作子对象。在你的表达式中你没有,但是因为Parent没有SetName方法,你的代码不会进行类型检查,所以它不会编译。
如果你做了转换,c#会检查类型以防万一,但它会做你想要的调用。