接口/抽象类中的静态方法
首先,我了解接口或者抽象类(在.NET / Cterminology中)不能具有抽象静态方法的原因。然后,我的问题更多地集中在最佳设计解决方案上。
我想要的是一组"帮助程序"类,它们都有自己的静态方法,这样,如果我从第三方供应商那里获得对象A,B和C,则可以使用诸如以下方法的帮助程序类
AHelper.RetrieveByID(string id); AHelper.RetrieveByName(string name); AHelper.DumpToDatabase();
由于我的AHelper,BHelper和CHelper类基本上都具有相同的方法,因此将这些方法移动到这些类随后派生的接口上似乎很有意义。但是,希望这些方法是静态的,这使我无法拥有通用的接口或者抽象类,以供所有方法或者方法派生。
我总是可以使这些方法成为非静态的,然后首先实例化对象,例如
AHelper a = new AHelper(); a.DumpToDatabase();
但是,这段代码对我来说似乎并不直观。我们有什么建议?我应该完全放弃使用接口还是抽象类(我现在所处的状况),或者可以将其重构以完成我正在寻找的设计?
解决方案
回答
在C3.0中,可以使用扩展方法在接口上使用静态方法,就好像它们是接口的一部分一样,如下面的DumpToDatabase()所示:
static class HelperMethods { //IHelper h = new HeleperA(); //h.DumpToDatabase() public static void DumpToDatabase(this IHelper helper) { /* ... */ } //IHelper h = a.RetrieveByID(5) public static IHelper RetrieveByID(this ObjectA a, int id) { return new HelperA(a.GetByID(id)); } //Ihelper h = b.RetrieveByID(5) public static IHelper RetrieveByID(this ObjectB b, int id) { return new HelperB(b.GetById(id.ToString())); } }
回答
我个人可能会问,为什么在进一步思考之前,每种类型都需要有一个静态方法。
为什么不使用它们需要共享的静态方法创建utlity类呢? (例如," ClassHelper.RetrieveByID(字符串ID)"或者" ClassHelper <ClassA> .RetrieveByID(字符串ID)")
以我对这类"路障"的经验,问题不是语言的局限性,而是设计的局限性。
回答
ObjectA和AHelper有什么关系? AHelper.RetrieveByID()与BHelper.RetrieveByID()具有相同的逻辑
如果是,那么基于实用程序类的方法(仅具有公共静态方法且没有状态的类)如何?
static [return type] Helper.RetrieveByID(ObjectX x)
回答
如何发布有关堆栈溢出的反馈?编辑我的原始帖子还是发布"答案"?无论如何,我认为举个例子说明AHelper.RetrieveByID()和BHelper.RetreiveByID()可能会有所帮助
基本上,这两种方法都与第三方Web服务相冲突,后者使用Query方法返回各种通用(可广播)对象,而Query方法将伪SQL字符串作为唯一参数。
因此,AHelper.RetrieveByID(string ID)可能看起来像
public static AObject RetrieveByID(string ID) { QueryResult qr = webservice.query("SELECT Id,Name FROM AObject WHERE Id = '" + ID + "'"); return (AObject)qr.records[0]; } public static BObject RetrieveByID(string ID) { QueryResult qr = webservice.query("SELECT Id,Name,Company FROM BObject WHERE Id = '" + ID + "'"); return (BObject)qr.records[0]; }
希望有帮助。如我们所见,这两种方法是相似的,但是根据返回的对象类型不同,查询可能会有很大不同。
哦,罗布,我完全同意-这很可能是我设计的限制,而不是语言的限制。 :)
回答
我们是否正在寻找多态行为?然后,我们需要接口和普通的构造函数。关于调用构造函数的直觉是什么?如果我们不需要多态性(听起来像现在不使用它),则可以坚持使用静态方法。如果这些都是供应商组件周围的包装器,那么我们可能尝试使用工厂方法来创建它们,例如VendorBuilder.GetVendorThing(" A"),它可以返回IVendorWrapper类型的对象。
回答
我们不能仅通过更改返回类型来重载方法。
我们可以使用其他名称:
static AObject GetAObject(string id); static BObject GetBObject(string id);
或者,我们可以使用强制转换运算符创建一个类:
class AOrBObject { string id; AOrBObject(string id) {this.id = id;} static public AOrBObject RetrieveByID(string id) { return new AOrBObject(id); } public static AObject explicit operator(AOrBObject ab) { return AObjectQuery(ab.id); } public static BObject explicit operator(AOrBObject ab) { return BObjectQuery(ab.id); } }
然后我们可以这样称呼它:
var a = (AObject) AOrBObject.RetrieveByID(5); var b = (BObject) AOrBObject.RetrieveByID(5);
回答
查看回复,我在考虑以下方面:
- 我们可能只有一个静态方法,该方法采用类型参数,并根据类型执行预期的逻辑。
- 我们可以在抽象库中创建一个虚拟方法,在具体类中指定SQL。因此,它包含了将子类中的"专家"位(例如SQL)封装起来时,两者都需要的所有通用代码(例如,执行命令并返回对象)。
我更喜欢第二种选择,尽管它当然取决于我们。如果我们需要我进一步详细说明,请让我知道,我将很乐意进行编辑/更新:)
回答
对于示例的通用解决方案,我们可以执行以下操作:
public static T RetrieveByID<T>(string ID) { var fieldNames = getFieldNamesBasedOnType(typeof(T)); QueryResult qr = webservice.query("SELECT "+fieldNames + " FROM " + tyepof(T).Name +" WHERE Id = '" + ID + "'"); return (T) qr.records[0]; }
回答
如果我是你,我会尽量避免任何静电。恕我直言,我总是在静态问题上最终遇到某种同步问题。话虽这么说,我们正在展示一个使用模板的通用编程的经典示例。我将采用上一篇文章中介绍的Rob Copper的基于模板的解决方案。
回答
值得一提的是,贾斯汀(Justin)已经说过,SQL根据类型的不同而有很大的不同,因此我在工作的基础上,对类型的依赖可能完全不同,因此将其委托给相关的子类。而解决方案将SQL VERY与类型紧密耦合(即它是SQL)。
rptony关于静态的可能同步问题的要点,我没有提到,所以谢谢我们:)另外,它的Rob Cooper(不是Copper)BTW;):D(编辑:我想我会提到,以防万一。错字了,我希望是这样,所以没问题!)