>백엔드 개발 >C#.Net 튜토리얼 >C# 기본 수율 및 싱글톤

C# 기본 수율 및 싱글톤

黄舟
黄舟원래의
2017-02-07 17:03:361253검색

1. Yield의 역할 예시 분석

최근 Java 필기 테스트에서 처음으로 Yield 키워드를 접했으니 꼭 숙지해야 할 내용입니다. C#의 Yield 키워드 중 하나입니다. Yield 키워드는 반복자 블록에서 작동하며 가장 중요한 기능은 두 가지입니다. 하나는 열거 개체에 "순차적으로" 값을 제공하는 것이고, 다른 하나는 반복의 끝을 알리는 것입니다. 이 두 함수에 해당하는 문은 각각 Yield Return 및 Yield Break입니다.

아래에는 Yield를 사용하지 않는 경우와 Yield를 사용하는 경우의 두 가지 작은 예가 있습니다. 먼저 첫 번째를 살펴보겠습니다. 디버깅할 때 GetResult() 메서드가 실행되면 메서드 내부로 점프하여 실행을 완료한 다음 출력 현재 값 문을 실행한다는 것이 분명했습니다. 결과에서 볼 수 있듯이 첫 번째는 0입니다. 이는 반환된 열거 번호의 위치가 컬렉션에서 0이라는 것을 의미하며, 그 다음에는 내가 원하는 순회 데이터, 즉 열거 번호는 다음까지 변경되지 않습니다. MoveNext()가 호출됩니다. 다음 값을 얻기 위해 계속 앞으로 이동하지만 이제 데이터가 모두 메모리에 로드되었습니다.

두 번째 예를 다시 살펴보겠습니다. GetResultByYield() 메서드를 디버깅할 때 이 메서드 내부로 들어가고 싶었지만 다음 문장을 직접 실행하고 GetResultByYield를 입력하지 않은 것으로 나타났습니다. () 방법이 전혀 없습니다. 이때 result.Current가 null이고, 메소드 내부의 코드가 전혀 실행되지 않은 것으로 확인되어 이때 컬렉션이 비어 있는 것으로 추측했습니다. 디버깅을 계속하여 MoveNext() 메서드 실행 시 GetResultByYield()를 실행한 후, Yield return을 실행한 후 main() 메서드로 반환하여 열거자가 나타내는 집합의 값을 출력합니다.

위에서 볼 수 있듯이 MoveNext() 호출이 필요한 경우에만 메소드가 실행되어 결과를 가져옵니다. 사용하지 않으면 결과가 없습니다. 여기에서 컴파일러는 for 루프가 마지막 항복 반환이 중지된 상태에서 계속 실행되도록 보장하기 위해 반복자의 상태를 저장하는 상태 머신을 갖게 됩니다. 이 과정은 샤오팡이 1리터의 물을 마시고 싶어하는 것과 같습니다. 1리터 컵으로 마신다면 1리터 용기를 준비하고 정수기에서 1리터의 물을 채워야 합니다.

샤오팡이 음료의 절반을 마시고 다 마시지 못하면 나머지 물은 재활용되므로 첫 번째 예와 마찬가지로 다 마실 수 있는지 여부에 관계없이 물 1리터를 준비해야 합니다. 이제 컵의 부피를 0.2리터로 줄이세요. Xiaofang은 컵을 마신 후 물을 얻기 위해 정수기로 가서 매번 0.2리터만 마십니다. 이런 식으로 물을 마시고 싶을 때만 물을 가져오게 되는데, 마시는 도중에 물을 마시고 싶지 않다면 두 번째 예와 마찬가지로 첫 번째 방법에 비해 분명히 더 많은 물을 낭비하게 될 것입니다. 마지막으로, 조건에 따라 데이터가 더 이상 필요하지 않을 때 Yield Return을 호출하여 while 루프에서 벗어날 수 있습니다. Yield Break를 작성하지 않더라도 여전히 반복을 정상적으로 종료할 수 있습니다.

///
    /// 不使用yield的时候
    ///
    class Program
    {
        static void Main(string[] args)
        {
            //得到一个迭代结果
            var result = GetResult();
            //输出当前的值
            Console.WriteLine(result.Current);
            Console.WriteLine("开始遍历");
            while (result.MoveNext())
            {
                Console.WriteLine(result.Current);
            }
            Console.WriteLine("遍历结束");
            Console.ReadLine();
        }
        //不使用yield来进行迭代
        static IEnumeratorint> GetResult()
        {
            var arr = new int[] { 1, 6, 8, 12,15};
            Listint> list = new Listint>();
            foreach (int item in arr)
            {
                if (item 12)
                    list.Add(item);
            }
            return list.GetEnumerator();
        }
 
    }

///
    /// 使用yield关键字
    ///
    class Program
    {
        static void Main(string[] args)
        {
            //得到一个迭代结果
            var result = GetResultByYield();
            //输出当前的值
            Console.WriteLine(result.Current);
            Console.WriteLine("开始遍历");
            while (result.MoveNext())
            {
                Console.WriteLine(result.Current);
            }
            Console.WriteLine("遍历结束");
            Console.ReadLine();  
        }
        //使用yield来进行迭代
        static IEnumerator GetResultByYield()
        {
            var arr = new int[] { 1,6,8,12,15};
            foreach (var item in arr)
            {
                yield return item;
                if (item == 12)
                    yield break;
            }
        }
 
    }

출력 결과는 다음과 같습니다.

C# 기본 수율 및 싱글톤

C# 기본 수율 및 싱글톤


2. In -깊이 수율

위의 두 번째 예를 Reflector 도구에 넣으면 다음 세 가지 코드가 생성됩니다. 첫 번째 문단은 완전한 Pragrom 클래스의 C# 코드이고, 두 번째 문단은 d__0 봉인 클래스의 C# 확장 코드이며, 세 번째 문단은 GetResultByYield() 메서드의 IL 코드입니다. 첫 번째 코드에서는 시스템이 자동으로 이상한 이름의 일부 필드를 선언하는 d__0 봉인 클래스를 생성하는 것을 볼 수 있지만 이 클래스에는 가장 중요한 MoveNext() 메서드와 Current 속성이 포함되어 있음을 분명히 알 수 있습니다.

두 번째 코드는 이 봉인 클래스의 C# 확장 코드입니다. 이 시점에서 독자들이 나와 같은 질문을 갖고 있는지 궁금합니다. 왜 봉인 클래스가 자동으로 생성되어야 합니까? 대답은 코드의 세 번째 부분에 있습니다. GetResultByYield() 메서드에서 배열이 순회되지 않고 배열을 생성하는 newarr 명령도 표시되지 않는 것을 볼 수 있습니다. 대신 newobj는 d__0의 인스턴스 개체를 만듭니다. 봉인된 수업. 디버깅 중에 GetResultByYield() 메서드가 전혀 입력되지 않은 이유는 실제 구현 코드가 봉인 클래스의 MoveNext() 메서드에 있기 때문입니다. 앞서 언급한 것처럼 수익률은 요청 시 취해지므로 각 수익률 반환 상태를 기록하려면 상태 머신이 필요합니다.

在MoveNext()方法中由于密封类构造函数传进去的是一个0(在第三段代码中可以看到),因此第一次进入到MoveNext方法时this.__state=0。此时current字段由于没赋值因此就是null了。接着创建数组并开始一个while循环(原来foreach就是while循环),在循环中给current字段赋值并让state字段值为2,最后返回true。拿Current属性时就是拿while循环中给current赋的值,再次进入这个方法内此时state等于2于是跳转到Label_0090,也就是进入while语句块中继续循环,这就是按需所取的原理。当遇到yield break后会先执行Dispose释放资源,再执行break语句跳出循环。可以看到上述这个过程就是一个状态机,而这个密封类是为建立一个状态机来生成的,现在我们自己也可以写出一个状态机了。

internal class Program
{
    // Methods
    public Program();
    private static IEnumerator GetResultByYield();
    private static void Main(string[] args);
 
    // Nested Types
    [CompilerGenerated]
    private sealed class d__0 : IEnumeratorobject>, IEnumerator, IDisposable
    {
        // Fields
        private int 1__state;
        private object 2__current;
        public int[] 7__wrap4;
        public int 7__wrap5;
        public int[] 5__1;
        public int 5__2;
 
        // Methods
        [DebuggerHidden]
        public d__0(int 1__state);
        private void m__Finally3();
        private bool MoveNext();
        [DebuggerHidden]
        void IEnumerator.Reset();
        void IDisposable.Dispose();
 
        // Properties
        object IEnumeratorobject>.Current { [DebuggerHidden] get; }
        object IEnumerator.Current { [DebuggerHidden] get; }
    }
}

private sealed class d__0 : IEnumeratorobject>, IEnumerator, IDisposable
{
    // Fields
    private int 1__state;
    private object 2__current;
    public int[] 7__wrap4;
    public int 7__wrap5;
    public int[] 5__1;
    public int 5__2;
 
    // Methods
    [DebuggerHidden]
    public d__0(int 1__state)
    {
        this.1__state = 1__state;
    }
 
    private void m__Finally3()
    {
        this.1__state = -1;
    }
 
    private bool MoveNext()
    {
        try
        {
            switch (this.1__state)
            {
                case 0:
                    this.1__state = -1;
                    this.5__1 = new int[] { 1, 6, 8, 12, 15 };
                    this.1__state = 1;
                    this.7__wrap4 = this.5__1;
                    this.7__wrap5 = 0;
                    while (this.7__wrap5 this.7__wrap4.Length)
                    {
                        this.5__2 = this.7__wrap4[this.7__wrap5];
                        this.2__current = this.5__2;
                        this.1__state = 2;
                        return true;
                    Label_0090:
                        this.1__state = 1;
                        if (this.5__2 == 12)
                        {
                            this.System.IDisposable.Dispose();
                            break;
                        }
                        this.7__wrap5++;
                    }
                    this.m__Finally3();
                    break;
 
                case 2:
                    goto Label_0090;
            }
            return false;
        }
        fault
        {
            this.System.IDisposable.Dispose();
        }
    }
 
    [DebuggerHidden]
    void IEnumerator.Reset()
    {
        throw new NotSupportedException();
    }
 
    void IDisposable.Dispose()
    {
        switch (this.1__state)
        {
            case 1:
            case 2:
                this.m__Finally3();
                break;
        }
    }
 
    // Properties
    object IEnumeratorobject>.Current
    {
        [DebuggerHidden]
        get
        {
            return this.2__current;
        }
    }
 
    object IEnumerator.Current
    {
        [DebuggerHidden]
        get
        {
            return this.2__current;
        }
    }
}

 .method private hidebysig static class [mscorlib]System.Collections.IEnumerator GetResultByYield() cil managed
    {
        .maxstack 1
        .locals init (
            [0] class ConsoleApplication1.Program/d__0 d__,
            [1] class [mscorlib]System.Collections.IEnumerator enumerator)
        L_0000: ldc.i4.0
        L_0001: newobj instance void ConsoleApplication1.Program/d__0::.ctor(int32)
        L_0006: stloc.0
        L_0007: ldloc.0
        L_0008: stloc.1
        L_0009: br.s L_000b
        L_000b: ldloc.1
        L_000c: ret
    }

3.单例模式

单例模式没什么好说的,当然如果深挖应该也是大有学问,其中我觉得比较好的一种写法如下。单例模式的代码我看过多次不过却没怎么写,结果真真写的时候再加上时间又有点紧最后写的一塌糊涂。以后写代码要兴平气和地去写,急躁的状态写不出什么好代码。当然总会有烦躁的时候,所以只能多写代码来让自己写出高质量的代码成为一种习惯!

class A
    {
        private static A instance = new A();
        public static A Instance
        {
            get { return A.instance; }
        }
    }

以上就是C#基础之yield与Singleton的内容,更多相关内容请关注PHP中文网(www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.