2009-06-29 111 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)他们以目前不了解哪些会伤害重用的方式扩展类功能。

相关问题