接口/抽象类中的静态方法

时间:2008-08-18 13:42:09

标签: .net abstract-class static-methods interface-design

首先,我理解为什么接口或抽象类(在.NET / C#术语中)不能具有抽象静态方法的原因。我的问题更侧重于最佳设计解决方案。

我想要的是一组“助手”类,它们都有自己的静态方法,如果我从第三方供应商那里得到对象A,B和C,我可以使用诸如

AHelper.RetrieveByID(string id);
AHelper.RetrieveByName(string name);
AHelper.DumpToDatabase();

由于我的AHelper,BHelper和CHelper类都基本上都有相同的方法,因此将这些方法移动到这些类然后派生的接口似乎是有意义的。但是,希望这些方法是静态的,使我无法使用通用接口或抽象类来导出所有这些方法。

我总是可以使这些方法非静态,然后首先实例化对象,例如

AHelper a = new AHelper();
a.DumpToDatabase();

但是,这段代码对我来说似乎并不直观。你有什么建议?我应该完全放弃使用接口或抽象类(我现在的情况)还是可以重构这些来完成我正在寻找的设计?

10 个答案:

答案 0 :(得分:5)

如果我是你,我会尽量避免任何静电。恕我直言,我总是以静态方式结束某种同步问题。话虽如此,您正在使用模板呈现通用编程的经典示例。我将在上面的一篇文章中介绍Rob Copper提供的基于模板的解决方案。

答案 1 :(得分:3)

关注your response我正在考虑以下几点:

  • 您可以使用一个静态方法,该方法接受一个类型参数并根据类型执行预期的逻辑。
  • 您可以在抽象基础中创建虚拟方法,在其中指定具体类中的SQL。因此,它包含两者所需的所有公共代码(例如,执行命令并返回对象),同时在子类中封装“专家”位(例如SQL)。

我更喜欢第二种选择,虽然它当然取决于你。如果您需要我进一步了解详情,请告诉我,我将很乐意编辑/更新:)

答案 2 :(得分:3)

对于您的示例的通用解决方案,您可以这样做:

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];
}

答案 3 :(得分:2)

我个人也许会质疑为什么每个类型在进一步思考之前都需要一个静态方法。

为什么不用他们需要共享的静态方法创建一个utlity类? (例如ClassHelper.RetrieveByID(string id)ClassHelper<ClassA>.RetrieveByID(string id)

根据我对这些“障碍”的体验,问题不在于语言的局限性,而在于我设计的局限性。

答案 4 :(得分:2)

ObjectA和AHelper如何相关? AHelper.RetrieveByID()的逻辑与BHelper.RetrieveByID()

的逻辑相同

如果是,那么基于实用工具类的方法(仅使用公共静态方法且没有状态的类)

static [return type] Helper.RetrieveByID(ObjectX x) 

答案 5 :(得分:2)

您不能仅通过改变返回类型来重载方法。

您可以使用不同的名称:

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); 

答案 6 :(得分:1)

在C#3.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())); 
     }
 }

答案 7 :(得分:0)

如何在Stack Overflow上发布反馈?编辑我的原始帖子或发布“答案”?无论如何,我认为可能有助于举例说明AHelper.RetrieveByID()和BHelper.RetreiveByID()

中发生了什么。

基本上,这两种方法都是针对使用Query方法返回各种通用(可转换)对象的第三方Web服务,该方法将伪SQL字符串作为唯一参数。

因此,AHelper.RetrieveByID(字符串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];
}

希望这会有所帮助。如您所见,这两种方法类似,但根据返回的不同对象类型,查询可能会有很大不同。

哦,Rob,我完全同意 - 这很可能是我设计的限制,而不是语言。 :)

答案 8 :(得分:0)

您在寻找多态行为吗?然后你会想要接口和普通的构造函数。调用构造函数有什么不直观的?如果你不需要多态(听起来你现在不使用它),那么你可以坚持使用静态方法。如果这些都是供应商组件的包装器,那么也许您可能会尝试使用工厂方法来创建它们,如VendorBuilder.GetVendorThing(“A”),它可以返回类型为IVendorWrapper的对象。

答案 9 :(得分:0)

marxidad请注意,Justin已经说过,SQL的变化很大程度上取决于类型,所以我的工作基础是完全不同依赖于类型,因此将其委托给相关的子类。鉴于您的解决方案将SQL 非常紧密地绑定到Type(即 SQL)。

rptony关于静力学可能同步问题的好点,我没有提到,所以谢谢你:)另外,它的Rob Cooper (不是铜)BTW;):D (编辑:以为我会提到,如果它不是一个错字,我希望它是,所以没问题!)