Frage

Lassen Sie uns sagen, ich habe

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

kann ich die folgende Klasse, die Methodensignatur zu erzwingen? (Nur beschworene Idee):

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]

Zweck: Ich habe bereits Attribute in Methoden meines Middle Jahre. Ich habe Methoden wie folgt aus:

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

dann auf Laufzeit, ich werde durchläuft die Methoden des all Middle und legt sie der Sammlung (Attribute hilft hier viel), ordnet sie dann auf winform Delegierter Funktionen (durch die Schnittstelle erleichtert, plugins-basiertes System) als geladen

Ich denke, wenn ich die Attribute machen mehr selbstbeschreibende, so kann der Compiler Inkonsistenzen fangen.

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

Ich denke, wenn die Methoden auf jeder Klasse setzen, wäre es zuviel des Guten sein, immer ein Objekt zu instanziiert Remoting. Und sie auf eigene Klasse setzen, könnte es schwieriger sein, die Wiederverwendung von Code zu erleichtern, lassen Sie uns sagen Invoice_Save einige Informationen müssen auf Receipt_Open. In der Tat habe ich auch hier einen Bericht (Kristall), die die Daten von Remoting Middle DataSet geholt, in der aufgerufenen Methode, wird es einige Informationen über andere Methoden und in einer eigenen Datensatz zusammenführen, werden sie alles geschehen auf Middle, keine mehr Rundreisen, alle sind auf Server-Seite (Middle-Tier) durchgeführt

War es hilfreich?

Lösung

Sie sowohl die FollowAttribute Sie in Ihrem Beispiel und schreiben dass könnte überprüfen, ob jede Methode, die mit diesem Attribut markiert ist dieselbe Signatur wie die genannten Delegierten hat. So soll es möglich sein.

Andere Tipps

Andere Antworten sind offensichtlich gültig, aber nichts wird Sie schützt gegen das Vergessen [Follow(AutoCompleteDelegate)] Attribut auf Ihrer Methode anzuwenden.

Ich glaube, Sie wäre besser dran machen Methoden in Klassen drehen, die eine Schnittstelle implementieren:

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

und verwenden Sie dann die Factory-Methode Muster Ihre "auto Beender" zu bekommen:

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

oder

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

Sobald Sie, dass Sie einen Blick auf Inversion of Control und Dependency Injection um die Liste zu vermeiden harte Kodierung haben könnten von Auto-Vervollständigen-Implementierungen in der Factory-Methode.

Dies ist keine Sprache-Funktion, aber ...

Dies ist etwas, das Sie Validierung tun könnten. Unit-Tests schreiben, die über die Klasse zu reflektieren und fehlschlagen, wenn die Signatur nicht die Attribut-Deklaration überein

Postsharp auch gibt Ihnen einige interessante Möglichkeiten für diese um Kompilierung zu tun. Ich weiß nicht, wie genau würden Sie es verwenden, aber ich vermute, man könnte ...

Ich würde fragen, warum Sie dies tun wollen würde. Wenn Sie durch Vererbung geändert werden nicht die Klasse möchten, können Sie es sich um eine versiegelte Klasse machen. Wenn Sie sich Sorgen machen über jemanden die Klasse in der Zukunft zu ändern haben Sie 1 von zwei Fällen. 1) Sie verstehen nicht, was sie tun; Nichts kann einen schlechten Programmierer zu tun, schlechte Dinge verhindern, wenn sie volle Herrschaft haben Programmtext zu bearbeiten. 2) Sie sind zur Verlängerung der Klasse Funktionalität in einer Weise, die Sie derzeit nicht verstehen, die die Wiederverwendung weh tut.

Attribute gespeichert werden als zusätzliche Meta-Informationen während der Kompilierung -. Sie sie zur Laufzeit abfragen können aber während der Kompilierung sie in nicht berücksichtigt werden

Sie können keine Methode durch ein Attribut auf sie beschränken. Sie können einschränken, wie das Attribut angewendet wird (das heißt nur auf Methoden, oder ob mehr als ein angewendet werden kann).

Ich würde vorschlagen, FxCop verwenden zu warnen, wenn die Attribute nicht übereinstimmen - wenn Sie die Art und Weise Ereignisse vorsichtig tun sein unterstützen Typ wirft:

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

Wäre ein gültiger Delegat sein.

Nein.

Eine Art.

Sie können dieses Verhalten nicht bei der Kompilierung bekommen. Sie können mit Attributen, schieben diese in einem einfachen Test Baum oder einen sofortigen Ausfall erzwingen, wenn die enthaltende Klasse instanziiert wird.

Betrachten Sie die zwei (schnell gehackt) Attribute:

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

Werfen EnforceConforms (typeof (myFavoriteClass)) auf eine Klasse und Konform (typeof (myFavoriteDelegate)) auf den einschlägigen Methoden und und (dies ist der Hacky Teil) typeof (myFavoriteClass) .GetCustomAttributes ( falsch). Sie könnten so in einem statischen Initialisierer tun „sehr schnell“ oder tun dies in einer Testklasse zum Scheitern verurteilt (das sieht für alle Methoden in der Montage mit dem EnforceConforms Attribute, wenn Sie Lust bekommen mögen).

Im Allgemeinen sollten Sie wahrscheinlich nicht verwenden. Wenn Ihr Design erfordert überprüfen Sie die richtige delegieren Implementierungen sollten Sie erneut Architekt, wenn möglich. Hinzu kommen die nicht-Kompilierung Bits davon machen, so dass Sie nicht wirklich selbst viel in der Art von Zeit zu sparen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top