[c#] C # 지연로드 자동 속성

C #에서는

자동 속성을 지정된 기본값을 사용하여 지연로드 된 자동 속성으로 전환하는 방법이 있습니까?

본질적으로 나는 이것을 돌리려고 노력하고 있습니다 …

private string _SomeVariable

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

          return _SomeVariable;
     }
}

기본값을 지정할 수 있고 나머지는 자동으로 처리합니다.

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



답변

아니 없어. 자동 구현 속성은 가장 기본적인 속성 인 getter 및 setter를 사용한 지원 필드 만 구현합니다. 이러한 유형의 사용자 지정을 지원하지 않습니다.

그러나 4.0 Lazy<T>유형을 사용하여이 패턴을 만들 수 있습니다.

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

이 코드는 표현식이 _someVariable처음 Value호출 될 때의 값을 느리게 계산합니다 . 한 번만 계산되며 향후 Value속성 사용을 위해 값을 캐시합니다.


답변

아마도 가장 간결한 것은 null-coalescing 연산자를 사용하는 것입니다.

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


답변

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


답변

그렇지 않으면 속성에 대한 매개 변수는 값이 일정해야하며 코드를 호출 할 수 없습니다 (정적 코드라도).

그러나 PostSharp의 Aspect로 무언가를 구현할 수 있습니다.

한번 봐봐:

PostSharp


답변

다음은 귀하의 문제에 대한 해결 방법입니다. 기본적으로 아이디어는 첫 번째 액세스시 함수에 의해 설정되는 속성이며 후속 액세스는 첫 번째 액세스와 동일한 반환 값을 생성합니다.

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

물론 함수 포인터를 전달하는 오버 헤드가 있지만, 그것은 나를 위해 일을하며 메서드를 반복해서 실행하는 것에 비해 너무 많은 오버 헤드를 느끼지 않습니다.


답변

저는이 아이디어의 열렬한 팬이며 proplazy.snippet이라고 부르는 다음 C # 스 니펫을 제공하고 싶습니다 (이 코드를 가져 오거나 스 니펫 관리자에서 가져올 수있는 표준 폴더에 붙여 넣을 수 있습니다).

다음은 출력 샘플입니다.

private Lazy<int> myProperty = new Lazy<int>(()=>1);
public int MyProperty { get { return myProperty.Value; } }

스 니펫 파일 내용은 다음과 같습니다. (proplazy.snippet으로 저장)

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>proplazy</Title>
            <Shortcut>proplazy</Shortcut>
            <Description>Code snippet for property and backing field</Description>
            <Author>Microsoft Corporation</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
                    <ToolTip>The variable backing this property</ToolTip>
                    <Default>myVar</Default>
                </Literal>
                <Literal>
                    <ID>func</ID>
                    <ToolTip>The function providing the lazy value</ToolTip>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>

            </Declarations>
            <Code Language="csharp"><![CDATA[private Lazy<$type$> $field$ = new Lazy<$type$>($func$);
            public $type$ $property$ { get{ return $field$.Value; } }
            $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>


답변

순수한 C #으로는 이것이 가능하지 않다고 생각합니다. 그러나 PostSharp 와 같은 IL 재 작성기를 사용하여 수행 할 수 있습니다. 예를 들어 속성에 따라 함수 앞뒤에 핸들러를 추가 할 수 있습니다.