10

首先,我了解接口或抽象类(在 .NET/C# 术语中)不能具有抽象静态方法的原因。然后我的问题更集中在最佳设计解决方案上。

我想要的是一组“帮助器”类,它们都有自己的静态方法,这样如果我从第三方供应商那里获得对象 A、B 和 C,我可以拥有带有方法的帮助器类,例如

AHelper.RetrieveByID(字符串 id);
AHelper.RetrieveByName(字符串名称);
AHelper.DumpToDatabase();

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

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

AHelper a = 新的 AHelper();
a.DumpToDatabase();

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

4

10 回答 10

5

如果我是你,我会尽量避免任何静态。恕我直言,我总是在静态的道路上遇到某种同步问题。话虽如此,您正在展示一个使用模板进行通用编程的经典示例。我将采用上面一篇文章中介绍的 Rob Copper 的基于模板的解决方案。

于 2008-08-18T14:30:19.777 回答
3

看了你的回复,我的想法是这样的:

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

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

于 2008-08-18T14:25:33.733 回答
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];
}
于 2008-08-18T14:30:03.053 回答
2

我个人可能会质疑为什么每种类型都需要有一个静态方法,然后再进一步思考......

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

根据我对这些“障碍”的经验,问题不是语言的限制,而是我设计的限制。

于 2008-08-18T13:53:27.010 回答
2

ObjectA 和 AHelper 有什么关系?是AHelper.RetrieveByID()一样的逻辑BHelper.RetrieveByID()

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

static [return type] Helper.RetrieveByID(ObjectX x) 
于 2008-08-18T13:57:02.260 回答
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); 
于 2008-08-18T14:18:22.797 回答
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())); 
     }
 }
于 2008-08-18T13:46:54.247 回答
0

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

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

所以, AHelper.RetrieveByID(string ID) 可能看起来像

公共静态 AObject RetrieveByID(字符串 ID)
{
  QueryResult qr = webservice.query("SELECT Id,Name FROM AObject WHERE Id = '" + ID + "'");

  返回(AObject)qr.records[0];
}

公共静态 BObject RetrieveByID(字符串 ID)
{
  QueryResult qr = webservice.query("SELECT Id,Name,Company FROM BObject WHERE Id = '" + ID + "'");

  返回 (BObject)qr.records[0];
}

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

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

于 2008-08-18T14:05:17.750 回答
0

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

于 2008-08-18T14:07:03.240 回答
0

marxidad需要注意一点,Justin 已经说过 SQL 因类型而异,所以我的工作是基于它可能完全不同,取决于类型,因此将其委托给有问题的子类. 而您的解决方案将 SQL与类型非常紧密地结合在一起(即它SQL)。

rptony关于静态可能的同步问题的好点,我没有提到,所以谢谢你:) 另外,它的 Rob Cooper(不是铜)顺便说一句;):D(编辑:只是想我会提到,以防万一' t一个错字,我希望它是,所以没问题!)

于 2008-08-18T14:42:11.407 回答