Pregunta

digamos que tengo

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

¿puedo hacer la siguiente clase para imponer esa firma de método? (solo una idea evocada):

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
    }         

}

[EDITAR]

Propósito: ya puse atributos en los métodos de mi middletier. Tengo métodos como este:

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

luego, en tiempo de ejecución, iteraré todos los métodos del middletier y los pondré en la colección (los atributos ayudan mucho aquí), luego los asignaré a las funciones de delegado de winform (facilitado por la interfaz, el sistema basado en complementos) como cargado

Estoy pensando si puedo hacer que los atributos sean más autodescriptivos, para que el compilador pueda detectar inconsistencias.

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

Estoy pensando si poner los métodos en cada clase, sería una exageración crear siempre una instancia de un objeto Remoting. Y ponerlos en una clase separada, podría ser más difícil facilitar la reutilización del código, digamos que Invoice_Save necesita información sobre Receipt_Open. De hecho, incluso tengo un informe aquí (crystal), que obtuvo datos del DataSet Remoting middletier, dentro del método invocado, obtiene información sobre otros métodos y se fusiona en su propio DataSet, todos están sucediendo en middletier, no hay varios viajes de ida y vuelta, todos se realizan en el lado del servidor (nivel medio)

¿Fue útil?

Solución

Puede implementar tanto el FollowAttribute que usa en su ejemplo como escriba un Análisis estático (por ejemplo, FxCop ) regla que podría verificar si algún método etiquetado con ese atributo tiene la misma firma que el delegado mencionado. Entonces debería ser posible.

Otros consejos

Otras respuestas son obviamente válidas, pero nada lo protegerá de olvidarse de aplicar el atributo [Follow(AutoCompleteDelegate)] en su método.

Creo que sería mejor convertir los métodos en clases que implementen una interfaz:

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

y luego use el patrón de método de fábrica para obtener su " finalizadores automáticos < !> quot ;:

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

o

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

Una vez que tenga eso, puede echar un vistazo a la inversión de control y la inyección de dependencia para evitar codificar la lista de implementaciones de autocompletado en su método de fábrica.

Esta no es una función de idioma, pero ...

Esto es algo para lo que podría validar: escriba pruebas unitarias que reflejen sobre la clase y fallen si la firma no coincide con la declaración del atributo.

PostSharp también le ofrece algunas opciones interesantes para hacer esto en torno a la compilación. No sé exactamente cómo lo usarías, pero sospecho que podrías ...

Me preguntaría por qué quieres hacer esto. Si no desea que la clase se cambie por herencia, puede convertirla en una clase sellada. Si le preocupa que alguien cambie la clase en el futuro, tiene 1 de dos casos. 1) No entienden lo que están haciendo; nada puede evitar que un mal programador haga cosas malas si tiene el reinado completo para editar el texto del programa. 2) Están ampliando la funcionalidad de clase de una manera que actualmente no entiendes, lo que perjudica la reutilización.

Los atributos se almacenan como metainformación adicional durante la compilación; puede consultarlos en tiempo de ejecución pero durante la compilación no se tienen en cuenta.

No puede restringir un método por un atributo en él. Puede restringir cómo se aplica el atributo (es decir, solo en los métodos o si se puede aplicar más de uno).

Sugeriría usar FxCop para advertir cuando los atributos no coinciden, si tiene cuidado con la forma en que los eventos admiten los tipos de conversión:

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

Sería un delegado válido.

No.

Más o menos.

No puede obtener este comportamiento en tiempo de compilación. Puede, con Atributos, insertar esto en un arnés de prueba simple o forzar una falla inmediata cuando se instancia la clase que lo contiene.

Considere los dos atributos (rápidamente pirateados):

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

Lanza EnforceConforms (typeof (myFavoriteClass)) a una clase, y Conforms (typeof (myFavoriteDelegate)) a los métodos pertinentes y luego (esta es la parte hacky) typeof (myFavoriteClass) .GetCustomAttributes ( falso). Podría hacerlo en un inicializador estático para fallar & Quot; realmente rápido & Quot; o hágalo en una clase de prueba (que busca todos los métodos en el ensamblaje con el atributo EnforceConforms si desea hacerse más elegante).

Generalmente, probablemente no deberías usar esto. Si su diseño requiere que verifique las implementaciones de delegado adecuadas, debe rediseñar si es posible. Además, los fragmentos de tiempo sin compilación hacen que realmente no se ahorre mucho en el camino del tiempo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top