Question

disons que j'ai

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

puis-je créer la classe suivante pour appliquer cette signature de méthode? (juste une idée évoquée):

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
    }         

}

[EDIT]

Objectif: je mets déjà des attributs dans les méthodes de mon intermédiaire. J'ai des méthodes comme celle-ci:

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); 
}

puis au moment de l'exécution, j'itérerai toutes les méthodes du médiateur et les mettrai en collection (les attributs m'aidera beaucoup ici), puis les mapperai sur les fonctions de délégué de winform (facilitées par l'interface, le système à base de plugins) chargées

Je pense que si je peux rendre les attributs plus auto-descriptifs, afin que le compilateur puisse détecter les incohérences.

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);
    }
}

Je pense que, si les méthodes étaient appliquées à chaque classe, il serait excessif de toujours instancier un objet Remoting. Et en les plaçant sur des classes séparées, il pourrait être plus difficile de faciliter la réutilisation du code, supposons qu'Invoice_Save ait besoin d'informations sur Receipt_Open. En fait, j'ai même un rapport ici (crystal), qui récupérait des données de Remoting middletier DataSet, dans la méthode invoquée, il obtenait des informations sur d'autres méthodes et fusionnait dans son propre DataSet, elles se produisaient toutes sur middletier, pas plusieurs allers-retours, tout est fait sur le côté serveur (niveau intermédiaire)

Était-ce utile?

La solution

Vous pouvez implémenter le FollowAttribute que vous utilisez dans votre exemple et rédiger une analyse statique (par exemple, FxCop ) règle permettant de vérifier si une méthode marquée avec cet attribut a la même signature que le délégué mentionné. Cela devrait donc être possible.

Autres conseils

D'autres réponses sont évidemment valables, mais rien ne vous empêchera d'oublier d'appliquer l'attribut [Follow(AutoCompleteDelegate)] sur votre méthode.

Je pense que vous feriez mieux de transformer les méthodes en classes qui implémentent une interface:

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
    }
}

puis utilisez le modèle de méthode d'usine pour obtenir votre & "Auto-compléteurs < !> quot;:

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

ou

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.
    }
}

Une fois que vous avez compris, vous pouvez examiner l'inversion de contrôle et l'injection de dépendance afin d'éviter de coder en dur la liste des mises en œuvre à complétion automatique dans votre méthode d'usine.

Ce n'est pas une fonctionnalité linguistique, mais ...

C’est quelque chose pour lequel vous pouvez valider: écrire des tests unitaires qui reflètent la classe et échouer si la signature ne correspond pas à la déclaration de l’attribut.

PostSharp vous offre également quelques options intéressantes pour ce faire en matière de compilation. Je ne sais pas exactement comment vous l'utiliseriez, mais je suppose que vous pourriez ...

Je me demanderais pourquoi vous voudriez faire cela. Si vous ne voulez pas que la classe soit modifiée par héritage, vous pouvez en faire une classe scellée. Si vous craignez que quelqu'un change de classe à l'avenir, vous avez l'un des deux cas. 1) ils ne comprennent pas ce qu'ils font; rien ne peut empêcher un mauvais programmeur de faire de mauvaises choses s’il dispose du plein pouvoir pour éditer le texte du programme. 2) Ils étendent les fonctionnalités de la classe d’une manière que vous ne comprenez pas actuellement ce qui fait mal à la réutilisation.

Les attributs sont stockés sous forme de méta-informations supplémentaires lors de la compilation. Vous pouvez les interroger à l'exécution, mais ils ne sont pas pris en compte lors de la compilation.

Vous ne pouvez pas contraindre une méthode par un attribut. Vous pouvez restreindre la manière dont l’attribut est appliqué (c’est-à-dire uniquement sur les méthodes, ou si plusieurs peuvent être appliquées).

Je suggérerais d'utiliser FxCop pour avertir lorsque les attributs ne correspondent pas - si vous faites attention à la façon dont les événements supportent les transtypages:

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

Serait un délégué valide.

Non.

Type de.

Vous ne pouvez pas avoir ce comportement à la compilation. Vous pouvez, avec Attributes, insérer cela dans un simple harnais de test ou forcer un échec immédiat lorsque la classe qui le contient est instanciée.

Considérez les deux attributs (rapidement piratés):

[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");
    }
}

Jetez EnforceConforms (typeof (myFavoriteClass)) sur une classe et conforme (typeof (myFavoriteDelegate)) sur les méthodes pertinentes et then (c'est la partie hacky) typeof (myFavoriteClass) .GetCustomAttributes ( faux). Vous pouvez le faire dans un initialiseur statique pour échouer & "; Vraiment rapide &"; ou le faire dans une classe de test (qui recherche toutes les méthodes de l'assembly avec l'attribut EnforceConforms si vous voulez avoir du chic).

En général, vous ne devriez probablement pas utiliser ceci. Si votre conception nécessite que vous vérifiiez la bonne implémentation des délégués, vous devez réarchiver si possible. De plus, les temps de non-compilation en font une solution qui vous permet de ne pas économiser beaucoup de temps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top