C#Generics – 如何返回特定类型?
也许我说这一切都错了。
我有一堆派生自“Model”类的类,一个带有一堆常见属性和方法的基类。 我希望他们都实现一组function:
public abstract void Create(); public abstract T Read(Guid ID); //<--Focus on this one public abstract void Update(); public abstract void Delete();
然后我在像“约会”这样的子类中实现它,如下所示:
public override T Read(Guid ID) { var appt = db.Appointments.First(a => a.AppointmentID.Equals(ID)); var appointment = new Appointment() { DateEnd = appt.dateEnd.GetValueOrDefault(), Location = appt.location, Summary = appt.summary }; return appointment; }
这会引发exception“无法将类型’约会’隐式转换为T”。 如果我将方法的签名更改为“public override Appointment Read(Guid ID)”,那么编译器会说我没有在子类中实现抽象方法。
我错过了什么? 谁能给我一些代码示例?
看起来你可以使用通用基类! 考虑以下内容:
class Model { public abstract T Read(Guid ID); } class Appointment : Model { public override Appointment Read(Guid ID) { } }
现在你的子类都是强类型的。 当然,权衡是你不再拥有一个基类。 Model
与Model
。 我一般都没有发现这是一个问题,因为它没有什么共同的function – 接口是相似的,但它们都使用不同的类型。
如果你想要一个共同的基础,你当然可以欺骗并实现一个基于object
的界面来完成相同的一般任务。 例如,某种精神(未经测试,但想法在那里):
interface IModelEntity { object Read(Guid ID); } class Model : IModelEntity { public T Read(Guid ID) { return this.OnRead(ID); // Call the abstract read implementation } object IModelEntity.Read(Guid ID) { return this.OnRead(ID); // Call the abstract read implementation } protected abstract virtual T OnRead(Guid ID); } class Appointment : Model { protected override Appointment OnRead(Guid ID) { /* Do Read Stuff */ } }
这会有用吗?
public abstract T Read(Guid ID) where T : IAppointment;
你需要盒装和施法。 我想知道为什么这种方法是通用的?
return (T)(object)appointment;
你必须首先转向object
然后转向T
原因在于该object
位于inheritance链的顶端。 从Appointment
到T
没有直接关联; 因此你必须回溯到object
,然后找到回到T
。
我提供了这个答案来解释为什么返回陈述不会起作用,除非它被双重演绎 – 并且支持Chaos&Greg给出的答案
首先 ,我建议你把基类变成一个接口。 如果这是你的选择,这也会减少稍微混乱的代码,因为你可以摆脱接口声明中的abstract
和public
关键字,并省略实现类中的override
。
其次 ,正如您对Appointment.Read
的实现所暗示的那样,您可以更改Read
的方法签名以返回模型对象。
两个建议的更改都将导致以下结果:
public interface IModel { void Create(); IModel Read(Guid ID); void Update(); void Delete(); }
第三 ,在我看来, Read
应该是一种工厂方法。 在当前代码中,您需要首先实例化一个Appointment
对象,然后才能调用Read
方法来检索另一个Appointment
对象。 从课堂设计的角度来看,这对我来说似乎是错误的。
如何将Read
从基类/接口中取出并在所有派生/实现类中将其作为静态方法提供? 例如:
public class Appointment : IModel { public static Appointment Read(Guid ID) { return new Appointment() { ... }; } }
您还可以考虑将Read
移动到静态(工厂)类中; 然而,它必须足够聪明才能知道它应该返回什么样的对象。 这将有效,例如,如果您的数据库中有一个表将GUID映射到相应的对象类型。
编辑 :上面的最后一条建议曾经是这样的:
第三,如果到目前为止这是正确的,那么接下来的问题是Read
是否应该是静态方法。 如果是这样,它可以变为static
并移动到静态Model
类中。 然后,该方法就像一个从DB构建IModel
对象的工厂方法:
Guid guid = ...; IModel someModel = Model.Read(guid);
这个设计有点古怪。
无论Model
类是否是模板化的,在Read
方法上放置模板参数作为实例方法都没有多大意义。
通常你会有类似Greg D发布的内容。
如果public abstract T Read
Model
只会返回派生类型的Model
,考虑将签名更改为
public abstract class Model { public abstract void Create(); public abstract Model Read(Guid ID); //<--here public abstract void Update(); public abstract void Delete(); }
在您的约会课程中添加此项
public class Appointment : Model where T : Appointment
你也可以调用: var x = myModel.Read