2009-06-29 110 views
5

讓我們說我有有沒有一種方法可以強制執行特定方法簽名的方法?

public delegate DataSet AutoCompleteDelegate(
     string filter, long rowOffset); 

我可以做下面的類執行這一方法的簽名? (只是編造了主意):

public class MiddleTier 
{ 
    [Follow(AutoCompleteDelegate)] 
    public DataSet Customer_AutoComplete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 

    [Follow(AutoCompleteDelegate)] 
    public DataSet Item_AutoComplete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 



    // this should give compilation error, doesn't follow method signature 
    [Follow(AutoCompleteDelegate)] 
    public DataSet BranchOffice_AutoComplete(string filter, string rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    }   

} 

[編輯]

目的:我已經把我的middletier的方法屬性。我有這樣的方法:

public abstract class MiddleTier : MarshalByRefObject 
{ 
    // Operation.Save is just an enum 

    [Task("Invoice", Operation.Save)] 
    public Invoice_Save(object pk, DataSet delta); 

    [Task("Receipt", Operation.Save)] 
    public Receipt_Save(object pk, DataSet delta); 


    // compiler cannot flag if someone deviates from team's standard 
    [Task("Receipt", Operation.Save)] 
    public Receipt_Save(object pk, object[] delta); 
} 

然後在運行時,我會遍歷所有middletier的方法,並把它們集合(屬性有很大幫助,在這裏),然後映射他們的winform的委託功能(通過接口方便,基於插件的系統)作爲加載

我在想如果我可以使屬性更自我描述,所以編譯器可以捕獲不一致。

namespace Craft 
{   
    // public delegate DataSet SaveDelegate(object pk, DataSet delta); // defined in TaskAttribute 

    public abstract class MiddleTier : MarshalByRefObject 
    { 

     [Task("Invoice", SaveDelegate)]   
     public abstract Invoice_Save(object pk, DataSet delta); 

     [Task("Receipt", SaveDelegate)] 
     // it's nice if the compiler can flag an error 
     public abstract Receipt_Save(object pk, object[] delta); 
    } 
} 

我在想,如果把方法上的每個類,這將是一個矯枉過正總是實例化一個遠程對象。將它們放在單獨的類中,可能會更難以促進代碼重用,比方說,Invoice_Save需要有關Receipt_Open的一些信息。事實上,我甚至在這裏有一個報告(crystal),它在調用的方法內部獲取來自Remoting middletier DataSet的數據,獲取其他方法的一些信息併合併到它自己的DataSet中,它們都發生在middletier上,沒有多次往返,所有人都在服務器端(中間層)

+0

這是什麼語言? – hlovdal 2009-06-29 07:08:14

+0

語言是C# – Hao 2009-06-29 07:12:46

回答

3

您可以實現做既FollowAttribute你在你的例子,write a Static Analysis (say, FxCop) rule使用可以檢查是否是被標記與屬性的任何方法具有相同的簽名提到的委託。所以它應該是可能的。

1

這是不是一種語言功能,但...

這是你可以做的驗證:寫單元測試,反映了階級,如果簽名不匹配的屬性聲明失敗。

PostSharp也給你一些圍繞編譯做這個有趣的選擇。我不知道你會如何使用它,但我懷疑你可以...

11

其他答案顯然是有效的,但沒有什麼會防止你忘記在你的方法中應用[Follow(AutoCompleteDelegate)]屬性。

我想你會過得更好使轉向方法爲類實現一個接口:

public interface IAutoComplete 
{ 
    DataSet Complete(string filter, long rowOffset); 
} 

public class CustomerAutoComplele : IAutoComplete 
{ 
    public DataSet Complete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 
} 

,然後使用factory method pattern讓你的「自動完成者」:

public static class AutoCompleteFactory 
{ 
    public static IAutoComplete CreateFor(string purpose) 
    { 
     // build up and return an IAutoComplete implementation based on purpose. 
    } 
} 

public static class AutoCompleteFactory 
{ 
    public static IAutoComplete CreateFor<T>() 
    { 
     // build up and return an IAutoComplete implementation based on T which 
     // could be Customer, Item, BranchOffice class. 
    } 
} 

一旦你有了,你可以看看inver控制和依賴注入的避免,以避免硬編碼工廠方法中的自動完成實現列表。

0

屬性被存儲在編譯過程中額外的元信息 - 你可以在運行時對它們進行查詢,但在編譯過程中,他們沒有在因素

您無法通過它的屬性約束的方法。您可以限制應用該屬性的方式(即僅限於方法,或者是否可應用多個屬性)。

我會建議使用FxCop的警告時,屬性不匹配 - 如果你不小心的方式對事件的支持類型轉換:

[Follow(AutoCompleteDelegate)] 
public DataSet Customer_AutoComplete(string filter, int rowOffset) 

將是一個有效的委託。

0

編號

排序

在編譯時您無法獲得此行爲。您可以使用Attributes將其推入簡單的測試工具中,或者在實例化包含類時強制立即失敗。

考慮兩個(快速黑客攻擊)屬性:

[AttributeUsage(AttributeTargets.Class)] 
public class EnforceConforms : Attribute 
{ 
    public EnforceConforms(Type myClass) 
     : base() 
    { 
     MethodInfo[] info = myClass.GetMethods(); 

     foreach (MethodInfo method in info) 
     { 
      object[] objs = method.GetCustomAttributes(false); 

      foreach (object o in objs) 
      { 
       Attribute t = (Attribute)o; 

       if (t.GetType() != typeof(ConformsAttribute)) continue; 

       MethodInfo mustConformTo = ((ConformsAttribute)t).ConformTo; 

       ParameterInfo[] info1 = mustConformTo.GetParameters(); 
       ParameterInfo[] info2 = method.GetParameters(); 

       bool doesNotCoform = false; 

       doesNotCoform |= (mustConformTo.ReturnType != method.ReturnType); 
       doesNotCoform |= (info1.Length != info2.Length); 

       if (!doesNotCoform) 
       { 
        for (int i = 0; i < info1.Length; i++) 
        { 
         ParameterInfo p1 = info1[i]; 
         ParameterInfo p2 = info2[i]; 

         if (!p1.ParameterType.Equals(p2.ParameterType)) 
         { 
          doesNotCoform = true; 
          break; 
         } 
        } 
       } 

       if (doesNotCoform) 
       { 
        throw new Exception(myClass.Name + "." + method.Name + " does not conform to required delegate signature"); 
       } 
      } 
     } 
    } 
} 

[AttributeUsage(AttributeTargets.Method)] 
public class ConformsAttribute : Attribute 
{ 
    public MethodInfo ConformTo; 

    public ConformsAttribute(Type type) 
     : base() 
    { 
     if (type.BaseType != typeof(Delegate) && type.BaseType != typeof(System.MulticastDelegate)) throw new Exception("Can only accept delegates"); 

     ConformTo = type.GetMethod("Invoke"); 
    } 
} 

擲EnforceConforms(typeof運算(myFavoriteClass))到一個類,並且符合(typeof運算(myFavoriteDelegate))到所述相關的方法和然後(此是hacky部分)typeof(myFavoriteClass).GetCustomAttributes(false)。您可以在靜態初始化程序中這樣做,以便在測試類中失敗(「非常快」),或者在測試類中執行此操作(如果想獲得幻想,它將使用EnforceConforms屬性查找程序集中的所有方法)。

一般來說,你可能不應該使用這個。如果你的設計需要你檢查適當的代表實現,你應該儘可能重新構建。再加上它的非編譯時間位,這樣你就不會真正節省時間。

1

我會問你爲什麼要這樣做。如果你不想通過繼承來改變這個類,你可以把它變成一個密封的類。如果您擔心將來有人更換班級,您將會遇到兩種情況中的一種。 1)他們不明白他們在做什麼;沒有任何東西可以防止壞程序員如果完全統治編輯程序文本,就不會做壞事。 2)他們以目前不瞭解哪些會傷害重用的方式擴展類功能。

相關問題