2010-10-27 4 views
63

В C#,C# Ленивый Loaded Автоматических Свойств

Есть ли способ, чтобы включить автоматическое свойство в ленивое загруженное автоматическое имущество с заданным значением по умолчанию?

По существу, я пытаюсь превратить это ...

private string _SomeVariable 

public string SomeVariable 
{ 
    get 
    { 
      if(_SomeVariable == null) 
      { 
      _SomeVariable = SomeClass.IOnlyWantToCallYouOnce(); 
      } 

      return _SomeVariable; 
    } 
} 

в нечто другое, где я могу указать по умолчанию, и он автоматически обрабатывает все остальное ...

[SetUsing(SomeClass.IOnlyWantToCallYouOnce())] 
public string SomeVariable {get; private set;} 
+0

@Gabe: Обратите внимание, что класс будет вызываться только один раз, если он никогда не будет возвращен урны null. – RedFilter

+0

Я обнаружил, что ... похоже, использует одноэлементный шаблон – ctorx

ответ

80

Нет, нет. Автоматически реализованные свойства работают только для реализации самых основных свойств: поля поддержки с геттером и сеттер. Он не поддерживает этот тип настройки.

Однако вы можете использовать тип 4.0 Lazy<T> создать этот паттерн

private Lazy<string> _someVariable =new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 
public string SomeVariable { 
    get { return _someVariable.Value; } 
} 

Этот код будет лениво вычислить значение _someVariable в первый раз выражение Value называется. Он будет вычисляться только один раз и будет кэшировать значение для использования в будущем Value.

+1

На самом деле мне кажется, что Lazy реализует одноэлементный шаблон. Это не моя цель ... моя цель - создать ленивое загруженное свойство, которое лениво создается, но расположено вместе с экземпляром класса, в котором он живет. Кажется, Лэйз не выполняет этого. – ctorx

+12

@ctorx Lazy не имеет ничего общего с шаблоном singleton. Он делает именно то, что вы хотите. – Stijn

+4

Примечание: 'SomeClass.IOnlyWantToCallYouOnce' в вашем примере должен быть статическим, который будет использоваться с инициализатором поля. –

2

Я надеваю Не думаю, что это возможно с чистым C#. Но вы можете сделать это с использованием переписывания IL, например PostSharp. Например, он позволяет добавлять обработчики до и после функций в зависимости от атрибутов.

5

Не так, параметры для атрибутов должны быть постоянными по значению, вы не можете вызвать код (даже статический код).

Возможно, вы сможете реализовать что-то с аспектами PostSharp.

Проверьте их:

PostSharp

17

Вероятно, наиболее кратким вы можете получить использовать оператор нуль-коалесцирующий:

get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); } 
+4

В случае, когда 'IOnlyWantToCallYouOnce' возвращает' null', он будет вызывать его более одного раза. – JaredPar

+6

При использовании оператора с нулевым коалесцированием приведенный выше пример не будет выполнен. Правильный синтаксис: '_SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); '- обратите внимание на добавление скобки вокруг параметра' _SomeVariable', если оно равно null. –

4

Вот моя реализация решения вашей проблемы. В принципе идея - это свойство, которое будет задано функцией при первом доступе, и последующие обращения приведут к тому же возвращенному значению, что и первое.

public class LazyProperty<T> 
{ 
    bool _initialized = false; 
    T _result; 

    public T Value(Func<T> fn) 
    { 
     if (!_initialized) 
     { 
      _result = fn(); 
      _initialized = true; 
     } 
     return _result; 
    } 
} 

Затем использовать:

LazyProperty<Color> _eyeColor = new LazyProperty<Color>(); 
public Color EyeColor 
{ 
    get 
    { 
     return _eyeColor.Value(() => SomeCPUHungryMethod()); 
    } 
} 

Существует, конечно, накладные расходы передавая указатель на функцию вокруг, но это делает работу для меня, и я не замечаю слишком много накладных расходов по сравнению с работой метод снова и снова.

+0

Разве не имеет смысла придавать функции конструктору? Таким образом, вы не будете создавать его в очереди каждый раз, и вы можете использовать его после того, как вы его использовали в первый раз. –

+0

@ lund.mikkel да, это тоже сработает. Возможны варианты использования обоих подходов. – deepee1

+5

Если вы передадите функцию конструктору, то, как и класс Lite, .NET, функция, переданная в этом режиме, должна быть статической, я знаю, что во многих случаях это не соответствует моей конструкции. – crunchy

8

Существует новая функция в C# 6 называется Expression Bodied Auto-Properties, который позволяет писать ему немного чище:

public class SomeClass 
{ 
    private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 

    public string SomeVariable 
    { 
     get { return _someVariable.Value; } 
    } 
} 

Теперь можно записать в виде:

public class SomeClass 
{ 
    private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 

    public string SomeVariable => _someVariable.Value; 
} 
+0

В последнем разделе кода, инициализация на самом деле не лени. 'IOnlyWantToCallYouOnce' будет вызываться при построении каждый раз при создании экземпляра класса. –

+0

@TomBlodget Спасибо, вы правы –

+0

Так что в других словах это не лениво загружено? – Zapnologica

0

https://github.com/bcuff/AutoLazy использует Fody для дайте вам что-то вроде этого

public class MyClass 
{ 
    // This would work as a method, e.g. GetSettings(), as well. 
    [Lazy] 
    public static Settings Settings 
    { 
     get 
     { 
      using (var fs = File.Open("settings.xml", FileMode.Open)) 
      { 
       var serializer = new XmlSerializer(typeof(Settings)); 
       return (Settings)serializer.Deserialize(fs); 
      } 
     } 
    } 

    [Lazy] 
    public static Settings GetSettingsFile(string fileName) 
    { 
     using (var fs = File.Open(fileName, FileMode.Open)) 
     { 
      var serializer = new XmlSerializer(typeof(Settings)); 
      return (Settings)serializer.Deserialize(fs); 
     } 
    } 
} 
Смежные вопросы