2012-01-17 189 views
4

我希望類有一個名爲GetProduct的強制靜態方法,以便客戶端代碼可以接受類型並在檢查傳入類型實現名爲ICommandThatHasProduct的接口後安全地調用該靜態方法。在類型上實現靜態方法

看來,這是不可能的,所以現在我正在尋求幫助找到一種方法,我可以實現這一點。我知道我可以使用反射來查看我傳遞的類型是否包含一個名爲「GetProduct」的方法,但我希望有更多的面向對象的方法(即使用繼承)。

任何幫助將不勝感激!下面的代碼是僞c#,絕對不會編譯。

public interface ICommandThatHasProduct 
{ 
    object GetProduct(int id); 
} 

public abstract class Command : ICommandThatHasProduct 
{ 
    // I want to be able to make the GetProduct method static 
    // so that calling code can safely call it 
    public static object GetProduct(int id) 
    { 
     // do stuff with id to get the product 
    } 

    public object Execute() 
    { 
     CommandWillExecute(); 
    } 

    public abstract object CommandWillExecute(); 
} 

public class Program 
{ 
    public Program(Type type, int productId) 
    { 
     if(type == ICommandThatHasProduct) 
     { 
      // Create the args 
      var args = object[1]{ productId }; 

      // Invoke the GetProduct method and pass the args 
      var product = type.InvokeMethod("GetProduct", args); 

      //do stuff with product 
     } 

     throw new Execption("Cannot pass in a Command that does not implement ICommandHasProduct"); 
    } 
} 
+4

'static'方法並不真正適用於一般的面向對象的概念。 – 2012-01-17 03:15:05

+0

有沒有靜態繼承,所以反射可能是唯一的方法 – BrokenGlass 2012-01-17 03:16:10

+1

可能重複的[c#:繼承/接口靜態成員?](http://stackoverflow.com/questions/1128361/c-inherited-interface-static-member )事實上,幾乎所有的[這些問題](http://stackoverflow.com/search?q=%5Bc%23%5D+static+interface)已經解決了這個問題。 – 2012-01-17 03:26:11

回答

0

我認爲你真正的問題是你正在傳遞Type而不是你自己的一類。 GetProduct() - 方法實際上屬於表示命令類型的類,但當然不能將該方法添加到實際的Type中。所以相反,讓你自己的類來表示命令的類型。

我想你正在使用Type s通過反射來構建實際的Command。如果是這樣,你實際上需要一個'工廠'。 (如果製造工廠沒有意義,那麼只需創建一個'CommandType'對象)。

嘗試這樣:

public interface IFactory{ 
    object Create(); 
} 

public interface IFactoryThatHasProduct: IFactory 
{ 
    object GetProduct(int id); 
} 

public class MyCommand 
{ 
    //... 
} 

public class MyCommandFactory:IFactoryThatHasProduct 
{ 
    object Create(){ 
    return new MyCommand(); 
    } 

    object GetProduct(int id){ 
    return //TODO 
    } 
} 

public class Program 
{ 
    public Program(IFactory factory, int productId) 
    { 
    // consider just having the method take IFactoryThatHasProduct instead of IFactory 
    if(factory is IFactoryThatHasProduct){ 
     var factoryThatHasProduct = (IFactoryThatHasProduct) factory; 
     var product = factoryThatHasProduct.GetProduct(productId); 
    } 
    else{ 
     throw new Exception("Cannot pass in a factory that does not implement IFactoryThatHasProduct"); 
    } 
    } 
} 

}

3

方法不一定是靜態的。改用成員方法,並創建通常的繼承樹。

我猜你正在尋找abstract factory或C#中的簡單工廠方法模式實現。

記住LSP。它有助於避免奇怪的繼承樹。

0

考慮到這是否是正確的路要走,我會假設你知道你在做什麼。下面是一個最小的代碼示例:

using System; 
using System.Reflection; 

namespace EnforceStaticMethod 
{ 
class Program 
{ 
    static void Main() 
    { 
     var objA = GetProduct(typeof (TypeA), 1); 
     var objB = GetProduct(typeof (TypeB), 2); 

     Console.WriteLine("objA has type: " + objA.GetType()); 
     Console.WriteLine("objB has type: " + objB.GetType()); 
    } 

    static object GetProduct(Type type, int id) 
    { 
     var argTypes = new[] {typeof (int)}; 
     var method = type.GetMethod("GetProduct", BindingFlags.Static | BindingFlags.Public, null, argTypes, null); 
     if (method == null) 
     { 
      throw new ArgumentException("Type does not have GetProduct method: " + type); 
     } 

     var args = new object[] {id}; 
     return method.Invoke(null, args); 
    } 
} 

class TypeA 
{ 
    public static object GetProduct(int id) 
    { 
     return new TypeA(); 
    } 
} 

class TypeB 
{ 
    public static object GetProduct(int id) 
    { 
     return new TypeB(); 
    } 
} 
} 
3

我想一個類有一個名爲GetProduct強迫靜態方法,使客戶端代碼可以接受Type對象,並安全地調用靜態方法檢查所傳遞的類型後,實現一個接口。

您將通過Reflection進行呼叫,因此您將不得不通過Reflection來執行強制操作。 Reflection的全部要點是在編譯器無法驗證的運行時下工作;如果你想要的是編譯時驗證,那麼你正在使用錯誤的工具。不要使用專門設計的工具失敗編譯時驗證,如果這是你想要的東西!

我希望有一個更面向對象的方式(即使用繼承)。

你正在做它的面向對象的方式。面向對象是關於以對象形式傳遞函數單元,並向它們發送「消息」(又稱方法調用),它們描述了你想要對它們執行的操作,以及那些在晚些時候被分析的「消息」時尚。 (通常後期綁定是虛擬調用的形式,但後期的名稱綁定也可以。)

繼承是一種用於在類之間共享代碼並表示語義的機制「是一種」關係;你爲什麼覺得繼承與你的問題有關?

0

爲什麼你需要靜態調用它?你可以這樣做:

public class Client 
{ 
    public void DoSomethingWith<T>() where T : ICommandThatHasProduct, new() 
    { 
     var command = new T(); 
     var products = command.GetProducts(); 
    } 
} 

或者只是這樣的:

public class Client 
{ 
    public void DoSomethingWith(ICommandThatHasProduct command) 
    { 
     var products = command.GetProducts(); 
    } 
} 

可以實例總是傳遞到客戶端,而不是類型。

+0

由於構造函數的實際實現非常繁重,我不想僅僅爲了使用該方法而實例化它。 – Chris 2012-01-17 05:04:13

+0

如果您可以將這些方法用作靜態方法,那麼您將不會使用構造函數中的任何內容,所以...只需使用另一個具有該代碼的類即可。它會增加凝聚力並減少耦合。 – ivowiblo 2012-01-17 13:22:30

相關問題