Em C #,
Existe uma maneira de transformar uma propriedade automática em uma propriedade automática carregada lentamente com um valor padrão especificado?
Basicamente, estou tentando transformar isso ...
private string _SomeVariable
public string SomeVariable
{
get
{
if(_SomeVariable == null)
{
_SomeVariable = SomeClass.IOnlyWantToCallYouOnce();
}
return _SomeVariable;
}
}
em algo diferente, onde posso especificar o padrão e ele trata o resto automaticamente ...
[SetUsing(SomeClass.IOnlyWantToCallYouOnce())]
public string SomeVariable {get; private set;}
c#
automatic-properties
ctorx
fonte
fonte
Respostas:
Não, não há. As propriedades implementadas automaticamente funcionam apenas para implementar as propriedades mais básicas: campo de apoio com getter e setter. Não suporta este tipo de personalização.
No entanto, você pode usar o
Lazy<T>
tipo 4.0 para criar este padrãoEste código calculará preguiçosamente o valor da
_someVariable
primeira vez que aValue
expressão é chamada. Será calculado apenas uma vez e armazenará o valor em cache para usos futuros daValue
propriedadefonte
SomeClass.IOnlyWantToCallYouOnce
em seu exemplo deve ser estático para ser usado com um inicializador de campo.Provavelmente, o mais conciso que você pode obter é usar o operador de coalescência nula:
fonte
IOnlyWantToCallYouOnce
devoluçõesnull
, irá chamá-lo mais de uma vez._SomeVariable ?? ( _SomeVariable = SomeClass.IOnlyWantToCallYouOnce() );
- observe a adição do parêntese ao redor da configuração_SomeVariable
se for nulo.Lazy<>
, mas para nossos propósitos funcionou melhor. Com o C # mais recente, ele também pode ser escrito de forma ainda mais concisa.=> _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());
O que alguns podem não notar à primeira vista é que o operador avalia o operando à direita e retorna seu resultado .Há um novo recurso no C # 6 chamado Expression Bodied Auto-Properties , que permite que você escreva um pouco mais limpo:
Agora pode ser escrito como:
fonte
IOnlyWantToCallYouOnce
seria chamado durante a construção sempre que a classe fosse instanciada.SomeVariable
é carregado lentamente.Não assim, os parâmetros dos atributos devem ter valores constantes, você não pode chamar o código (Mesmo código estático).
No entanto, você pode ser capaz de implementar algo com Aspectos do PostSharp.
Confira:
PostSharp
fonte
Aqui está minha implementação de uma solução para o seu problema. Basicamente, a ideia é uma propriedade que será definida por uma função no primeiro acesso e os acessos subsequentes produzirão o mesmo valor de retorno do primeiro.
Então, para usar:
Obviamente, há a sobrecarga de passar o ponteiro de função, mas ele faz o trabalho para mim e não noto muita sobrecarga em comparação com a execução do método repetidamente.
fonte
Sou um grande fã dessa ideia e gostaria de oferecer o seguinte snippet C #, que chamei de proplazy.snippet. (Você pode importá-lo ou colá-lo na pasta padrão que pode obter no Gerenciador de trechos)
Aqui está um exemplo de sua saída:
Aqui está o conteúdo do arquivo de snippet: (salvar como proplazy.snippet)
fonte
Não acho que isso seja possível com C # puro. Mas você pode fazer isso usando um reescritor IL como o PostSharp . Por exemplo, permite adicionar manipuladores antes e depois das funções, dependendo dos atributos.
fonte
Eu fiz assim:
e depois você pode usá-lo como
fonte
public ISet<String> RegularProperty {get;set} public string CalculatedProperty => this.LazyValue(() => { return string.Join(",", RegularProperty.ToArray()); });
Operator ?? = está disponível em C # 8.0 e posterior, então agora você pode fazer de forma ainda mais concisa:
fonte
https://github.com/bcuff/AutoLazy usa Fody para dar a você algo assim
fonte
e eu chamo como abaixo
fonte
Se você usar um construtor durante a inicialização lenta, as extensões a seguir também podem ser úteis
Uso
fonte
LazyInitializer.EnsureInitialized()
? Porque pelo que posso dizer, além da funcionalidade acima,LazyInitializer
oferece tratamento de erros, bem como funcionalidade de sincronização. Código-fonte do LazyInitializer .