首先,我理解接口或抽象类(在.NET / C#术语中)不能具有抽象静态方法的原因。我的问题更侧重于最佳设计解决方案。
我想要的是一组"辅助"类,它们都有自己的静态方法,这样如果我从第三方供应商那里得到对象A,B和C,我可以使用诸如
1 2 3
| AHelper.RetrieveByID(string id);
AHelper.RetrieveByName(string name);
AHelper.DumpToDatabase(); |
由于我的AHelper,BHelper和CHelper类都基本上都有相同的方法,因此将这些方法移动到这些类随后派生的接口似乎是有意义的。但是,希望这些方法是静态的,使我无法使用通用接口或抽象类来导出所有这些方法。
我总是可以使这些方法非静态,然后首先实例化对象,如
1 2
| AHelper a = new AHelper();
a.DumpToDatabase(); |
但是,这段代码对我来说似乎并不直观。你有什么建议?我应该完全放弃使用接口或抽象类(我现在的情况)还是可以重构这些以完成我正在寻找的设计?
如果我是你,我会尽量避免任何静电。恕我直言,我总是以静态方式结束某种同步问题。话虽如此,您正在使用模板呈现通用编程的经典示例。我将在上面的一篇文章中介绍Rob Copper提供的基于模板的解决方案。
对于示例的通用解决方案,您可以执行以下操作:
1 2 3 4 5 6 7 8
| 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];
} |
看看你的回答我正在考虑以下几点:
-
你可以只有一个静态方法,它接受一个类型参数并根据类型执行预期的逻辑。
-
您可以在抽象基础中创建虚拟方法,在其中指定具体类中的SQL。因此,它包含两者所需的所有公共代码(例如,执行命令并返回对象),同时在子类中封装"专家"位(例如SQL)。
我更喜欢第二种选择,虽然它当然取决于你。如果您需要我进一步了解详情,请告诉我,我将很乐意编辑/更新:)
您不能通过改变返回类型来重载方法。
您可以使用不同的名称:
1 2
| static AObject GetAObject(string id);
static BObject GetBObject(string id); |
或者您可以使用强制转换运算符创建一个类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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);
}
} |
然后你可以像这样调用它:
1 2
| var a = (AObject) AOrBObject.RetrieveByID(5);
var b = (BObject) AOrBObject.RetrieveByID(5); |
ObjectA和AHelper如何相关? AHelper.RetrieveByID()与BHelper.RetrieveByID()的逻辑相同
如果是,那么基于Utility类的方法如何(仅使用公共静态方法且没有状态的类)
1
| static [return type] Helper.RetrieveByID(ObjectX x) |
我个人也许会质疑为什么每个类型在进一步思考之前都需要静态方法。
为什么不用他们需要共享的静态方法创建一个utlity类? (例如ClassHelper.RetrieveByID(string id)或ClassHelper.RetrieveByID(string id)
根据我对这类"障碍"的体验,问题不在于语言的局限性,而在于我设计的局限性。
在C#3.0中,静态方法可以在接口上使用,就好像它们是使用扩展方法的一部分一样,如下面的DumpToDatabase():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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()));
}
} |
marxidad只是一个快速的注意事项,Justin已经说过SQL的变化很大程度上取决于类型,所以我的工作基础是它可能是完全不同的类型,因此将它委托给有问题的子类。而你的解决方案非常紧密地将SQL与Type相连(即它是SQL)。
rptony关于可能与静力学同步问题的好点,我没有提到,所以谢谢你:)另外,它的Rob Cooper(不是铜)BTW;):D(编辑:只是想我会提到它以防万一'打字错误,我希望它是,所以没问题!)
您在寻找多态行为吗?然后你会想要接口和普通的构造函数。调用构造函数有什么不直观的?如果你不需要多态(听起来你现在不使用它),那么你可以坚持使用静态方法。如果这些都是供应商组件周围的包装器,那么您可能尝试使用工厂方法来创建它们,如VendorBuilder.GetVendorThing("A"),它可以返回类型为IVendorWrapper的对象。
如何在Stack Overflow上发布反馈?编辑我的原始帖子或发布"答案"?无论如何,我认为可能有助于举例说明AHelper.RetrieveByID()和BHelper.RetreiveByID()的情况。
基本上,这两种方法都针对第三方Web服务,它使用Query方法返回各种通用(可转换)对象,该方法接受伪SQL字符串作为其唯一参数。
因此,AHelper.RetrieveByID(字符串ID)可能看起来像
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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];
} |
希望这会有所帮助。如您所见,这两种方法类似,但根据返回的不同对象类型,查询可能会有很大不同。
哦,Rob,我完全同意 - 这很可能是我设计的限制,而不是语言。 :)