Pergunta

Digamos que eu tenho

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

Eu posso fazer a seguinte classe para impor que a assinatura método? (Apenas um conjurou idéia):

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]

Objetivo: Eu já colocar atributos em métodos de meu Intermediária. Eu tenho 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); 
}

, em seguida, em tempo de execução, eu vou iterar todos os métodos do Intermediária e colocá-los à colecção (atributos ajuda muito aqui), então mapeá-los em funções de delegado do winform (facilitada pela interface, sistema de plugins baseados) como carregado

Estou pensando se eu posso fazer os atributos mais auto-descrevendo, para que o compilador pode pegar inconsistências.

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

Estou pensando se colocando os métodos em cada classe, seria um exagero para sempre instanciar um objeto Remoting. E colocá-los na classe separada, que poderia ser mais difícil para facilitar a reutilização de código, digamos Invoice_Save precisar algumas informações sobre Receipt_Open. Na verdade eu ainda tenho um relatório aqui (cristal), que os dados obtidos a partir Remoting Intermediária DataSet, dentro do método invocado, ele recebe algumas informações sobre outros métodos e fundem-se em seu próprio DataSet, todos eles estão acontecendo na Intermediária, há várias idas e voltas, tudo é feito no lado do servidor (camada intermediária)

Foi útil?

Solução

Você poderia implementar tanto o FollowAttribute você usa no seu exemplo e escrever uma análise estática regra (por exemplo, FxCop) que poderia verificar se qualquer método que é marcado com esse atributo tem a mesma assinatura que o delegado mencionado. Por isso deve ser possível.

Outras dicas

Outras respostas são obviamente válido, mas nada irá proteger você contra o esquecimento de aplicar atributo [Follow(AutoCompleteDelegate)] em seu método.

Eu acho que você seria melhor fora de fazer métodos transformando-se em classes que implementam uma 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
    }
}

e, em seguida, usar o fábrica método padrão para obter seus "completaram Auto":

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

Uma vez que você tem que você poderia ter um olhar para inversão de controle e injeção de dependência para evitar rígido codificação a lista de auto implementações completas em seu método de fábrica.

Este não é um recurso de linguagem, mas ...

Este é algo que você poderia fazer a validação para:. Testes de unidade de gravação que refletem sobre a classe e falhar se a assinatura não coincide com a declaração de atributo

PostSharp também lhe dá algumas opções interessantes para fazer esta compilação ao redor. Eu não sei exatamente como você iria utilizá-lo, mas eu suspeito que você poderia ...

Gostaria de perguntar por que você iria querer fazer isso. Se você não quer que a classe a ser alterado através de herança, você pode torná-lo uma classe selada. Se você está preocupado com alguém alterar a classe no futuro você tem um de dois casos. 1) Eles não entendem o que estão fazendo; nada pode impedir que um programador ruim de fazer coisas ruins se eles têm pleno reinado de edição de texto programa. 2) Eles estão estendendo a funcionalidade de classe de uma forma que você não entende atualmente que fere reutilização.

Os atributos são armazenados como meta-informação extra durante a compilação -. Você pode consultá-los em tempo de execução, mas durante a compilação que não são tidas em conta

Você não pode restringir um método por um atributo nele. Você pode restringir a forma como o atributo é aplicado (ou seja, apenas em métodos, ou se mais de um pode ser aplicada).

Gostaria de sugerir usando FxCop para avisar quando os atributos não corresponderem - se você tomar cuidado com a forma como os eventos apoiar moldes do tipo:

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

seria um delegado válido.

Não.

Mais ou menos.

Você não pode obter este comportamento em tempo de compilação. Você pode, com atributos, enfiar isso em um chicote de fios simples teste ou forçar uma falha imediata quando a classe contendo é instanciado.

Considere os dois (rapidamente cortado) atributos:

[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 arremesso (typeof (myFavoriteClass)) para uma classe, e conforma (typeof (myFavoriteDelegate)) sobre os métodos pertinentes e (isto é a parte hacky) typeof .GetCustomAttributes (myFavoriteClass) ( falso). Você poderia fazê-lo em uma estática initializer a falhar "muito rápido", ou fazê-lo em uma classe de teste (que procura por todos os métodos na montagem com as EnforceConforms atribuem se você quiser começar a fantasia).

Geralmente, você provavelmente não deveria usar este. Se o seu projeto requer que você verifique implementações delegado adequadas você deve re-arquiteto, se possível. Além disso, os bits de tempo não-compilação de ele fazer isso para que você não está realmente salvar-se muito em termos de tempo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top