Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有一种方法可以强制方法遵循特定的方法签名?_C#_Design Patterns_Attributes_Enforcement - Fatal编程技术网

C# 有没有一种方法可以强制方法遵循特定的方法签名?

C# 有没有一种方法可以强制方法遵循特定的方法签名?,c#,design-patterns,attributes,enforcement,C#,Design Patterns,Attributes,Enforcement,假设我有 public delegate DataSet AutoCompleteDelegate( string filter, long rowOffset); 我可以创建以下类来强制该方法签名吗?(只是一个虚构的想法): [编辑] 目的:我已经在我的中间层方法中添加了属性。我有这样的方法: public abstract class MiddleTier : MarshalByRefObject { // Operation.Save is just an enum

假设我有

public delegate DataSet AutoCompleteDelegate(
      string filter, long rowOffset);
我可以创建以下类来强制该方法签名吗?(只是一个虚构的想法):

[编辑]

目的:我已经在我的中间层方法中添加了属性。我有这样的方法:

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); 
}
然后在运行时,我将迭代所有中间层的方法,并将它们放入集合(属性在这里非常有用),然后在加载时将它们映射到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);
    }
}

我在想,如果将方法放在每个类上,总是实例化远程处理对象将是一种过分的做法。如果将它们放在单独的类中,可能更难促进代码重用,比如说发票保存需要一些收据打开的信息。事实上,我这里甚至有一个报告(crystal),它从Remoting middletier数据集中获取数据,在调用的方法中,它获取其他方法的一些信息并合并到自己的数据集中,它们都发生在middletier上,没有几次往返,都是在服务器端(中间层)完成的

您可以实现示例中使用的
FollowAttribute
,并且可以检查标记了该属性的任何方法是否具有与所述委托相同的签名。所以这应该是可能的。

这不是语言功能,但是

这是您可以进行验证的事情:编写反映类的单元测试,如果签名与属性声明不匹配,则会失败


还提供了一些有趣的选项,用于围绕编译执行此操作。我不知道您将如何使用它,但我怀疑您可以…

其他答案显然是有效的,但没有什么可以防止您忘记在方法上应用
[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
    }
}
然后使用获取“自动完成器”:

公共静态类自动完成工厂
{
公共静态IAutoComplete CreateFor()
{
//建立并返回一个基于T的iautomplete实现
//可以是客户、项目、分支机构类别。
}
}

一旦有了这些,您就可以了解控制反转和依赖项注入,以避免在工厂方法中硬编码自动完成实现的列表。

属性在编译过程中存储为额外的元信息-您可以在运行时查询它们,但在编译过程中它们没有被考虑在内

不能通过方法上的属性约束方法。您可以限制属性的应用方式(即仅在方法上,或是否可以应用多个方法)

我建议使用FxCop在属性不匹配时发出警告-如果您确实注意事件支持类型强制转换的方式:

[Follow(AutoCompleteDelegate)]
public DataSet Customer_AutoComplete(string filter, int rowOffset)
将是有效的代理。

有点

在编译时无法获得此行为。您可以使用属性将其推入一个简单的测试工具中,或者在实例化包含的类时强制立即失败

考虑两个(快速入侵)属性:

[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");
    }
}
[AttributeUsage(AttributeTargets.Class)]
公共类EnforceConforms:属性
{
public EnforceConforms(类型myClass)
:base()
{
MethodInfo[]info=myClass.GetMethods();
foreach(信息中的MethodInfo方法)
{
object[]objs=method.GetCustomAttributes(false);
foreach(objs中的对象o)
{
属性t=(属性)o;
如果(t.GetType()!=typeof(ConformsAttribute))继续;
MethodInfo mustConformTo=((ConformsAttribute)t).ConformTo;
ParameterInfo[]info1=mustConformTo.GetParameters();
ParameterInfo[]info2=method.GetParameters();
bool doesnotform=false;
doesnotform |=(必须符合.ReturnType!=方法.ReturnType);
doesnotform |=(info1.Length!=info2.Length);
如果(!doesnotform)
{
for(int i=0;i
将EnforceCompliance(typeof(myFavoriteClass))抛出到类上,并将其(typeof(myFavoriteDelegate))抛出到相关方法上,然后(这是hacky部分)抛出typeof(myFavoriteClass)。GetCustomAttributes(false)。您可以在静态初始值设定项中执行此操作以“非常快”失败,也可以在测试类中执行此操作(如果您想获得更高的体验,它将查找程序集中具有EnforceConforms属性的所有方法)

一般来说,你可能不应该使用这个。如果您的设计要求您检查正确的委托实现,则应尽可能重新设计。再加上它的非编译时间部分,这样你就不会真正节省太多时间了
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.
    }
}
[Follow(AutoCompleteDelegate)]
public DataSet Customer_AutoComplete(string filter, int rowOffset)
[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");
    }
}