C#의 위임 해결

16674 단어 C#위임
자세히 보기
C#의 기본적인 특성에 대해 말하자면'위탁'은 어쩔 수 없이 이해하고 깊이 있게 분석해야 하는 특성이다.대부분의 신입 프로그래머들이'의뢰'에 대해 이야기할 때'방법을 방법의 매개 변수로 전달한다'는 생각을 한다. 간단한 정의만 아는 경우가 많다. 주로'의뢰'는 이해에 있어서 다른 특성보다 어려운 부분이 있기 때문이다.이번 설명에서는 위탁의 간단한 성명과 호출을 중점으로 하지 않는다.
'위탁' 은 실행할 행위를 직접 정의할 필요가 없고, 이 행위를 어떤 방법으로 대상에 포함시킬 수 있다.이 대상은 다른 어떤 대상처럼 사용할 수 있다.이 대상에서 봉인된 작업을 수행할 수 있습니다.의뢰를 하나의 방법으로 정의하는 인터페이스를 선택할 수 있고 의뢰의 실례를 그 인터페이스를 실현한 대상으로 볼 수 있다.
'위탁'의 관련 정의에서 우리는'위탁과 방법은'인터페이스와 유형'에 비해 디자인 이념상의 비슷한 부분을 가지고 있음을 알 수 있다.'디자인 원칙'중의'개방-폐쇄 원칙','개방-폐쇄'원칙: 소프트웨어 실체(클래스, 모듈, 함수 등)는 확장할 수 있으나 수정할 수 없다는 뜻이다.변경은 폐쇄적"이라며 새로운 수요에 직면해 프로그램에 대한 변경은 기존 코드를 변경하는 것이 아니라 새로운 코드를 추가하는 것으로 이뤄졌다.
C#에서 delegate 키워드 정의를 위탁하고 new 조작부호를 사용하여 위탁 실례를 구성하며 전통적인 방법으로 문법을 호출하여 함수를 리셋한다(위탁 대상의 변수로 방법명을 대체할 뿐).C#에서는 위임이 컴파일될 때 클래스로 컴파일됩니다.위탁에 대한 설명: 위탁은 하나의 종류로 방법의 유형을 정의하여 방법을 다른 방법의 매개 변수로 전달할 수 있다.위탁류는 하나의 유형에 끼워 넣을 수도 있고 전역적으로 정의할 수도 있다.위탁은 클래스이기 때문에 클래스를 정의할 수 있는 곳이라면 모두 위탁을 정의할 수 있다.
다음은'의뢰'의 구성, 만족해야 할 조건을 살펴보자.
     1.위임 유형을 선언합니다.
     2.실행할 코드를 포함하는 방법이 있어야 합니다.
     3.의뢰 실례를 만들어야 합니다.
     4.위탁 실례를 호출해야 합니다.
다음은 위에서 제시한 4가지 조건을 대략적으로 살펴보자.
위탁 형식은 실제적으로 매개 변수 형식의 목록과 되돌아오는 형식일 뿐입니다.유형의 실례가 표시할 수 있는 조작을 규정하였다.의뢰 실례를 호출할 때, 사용하는 매개 변수가 완전히 일치하고, 지정한 방식으로 되돌아오는 값을 사용할 수 있어야 한다.의뢰 실례의 창설은 조작이 실례 방법을 사용하느냐, 정적 방법을 사용하느냐에 따라 결정된다(조작이 정적 방법이라면 유형 이름을 지정하면 되고, 조작 실례 방법이라면 먼저 유형의 실례를 만들어야 한다).위탁의 호출에 대해 위탁의 실례를 직접 호출할 수 있는 방법으로 대응하는 조작을 완성할 수 있다.
위에서 언급한'의뢰'의 정의와 구성은 다음과 같다. 다음에 우리는 방법을'의뢰'에 어떻게 귀속시키는지, 그리고 의뢰의 합병과 삭제에 대해 알아보자.
여러 가지 방법을 같은 의뢰에 부여할 수 있으며 의뢰 실례는 실제적으로 하나의 조작 목록과 관련이 있다.시스템에서.Delegate 유형에는 두 가지 정적 방법인 Combine()과 Remove()가 의뢰 실례의 추가와 삭제 작업을 책임진다.그러나 우리의 실제 개발에서는 -=과 += 조작부호를 많이 사용한다.
FCL에서 모든 의뢰 유형은 MulticastDelegate에서 파생되며, 이 유형은 System에서 파생됩니다.MulticastDelegate 유형에 있습니다.
Combine() 메서드의 기본 구현 코드를 살펴보겠습니다.
 
[System.Runtime.InteropServices.ComVisible(true)] 
        public static Delegate Combine(params Delegate[] delegates) 
        {
            if (delegates == null || delegates.Length == 0) 
                return null;

            Delegate d = delegates[0];
            for (int i = 1; i < delegates.Length; i++) 
                d = Combine(d,delegates[i]);
 
            return d; 
        }

 
public static Delegate Combine(Delegate a, Delegate b) 
        {
            if ((Object)a == null) 
                return b;

            return  a.CombineImpl(b);
        }

위의 두 가지 방법은 System입니다.Delegate 형식에서 CombineImpl 방법은MulticastDelegate에서 다시 씁니다.
[System.Security.SecuritySafeCritical]  
        protected override sealed Delegate CombineImpl(Delegate follow)
        { 
            if ((Object)follow == null) 
                return this;
            if (!InternalEqualTypes(this, follow))
                throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis"));
 
            MulticastDelegate dFollow = (MulticastDelegate)follow;
            Object[] resultList; 
            int followCount = 1; 
            Object[] followList = dFollow._invocationList as Object[];
            if (followList != null) 
                followCount = (int)dFollow._invocationCount;

            int resultCount;
            Object[] invocationList = _invocationList as Object[]; 
            if (invocationList == null)
            { 
                resultCount = 1 + followCount; 
                resultList = new Object[resultCount];
                resultList[0] = this; 
                if (followList == null)
                {
                    resultList[1] = dFollow;
                } 
                else
                { 
                    for (int i = 0; i < followCount; i++) 
                        resultList[1 + i] = followList[i];
                } 
                return NewMulticastDelegate(resultList, resultCount);
            }
            else
            { 
                int invocationCount = (int)_invocationCount;
                resultCount = invocationCount + followCount; 
                resultList = null; 
                if (resultCount <= invocationList.Length)
                { 
                    resultList = invocationList;
                    if (followList == null)
                    {
                        if (!TrySetSlot(resultList, invocationCount, dFollow)) 
                            resultList = null;
                    } 
                    else 
                    {
                        for (int i = 0; i < followCount; i++) 
                        {
                            if (!TrySetSlot(resultList, invocationCount + i, followList[i]))
                            {
                                resultList = null; 
                                break;
                            } 
                        } 
                    }
                } 
                if (resultList == null)
                {
                    int allocCount = invocationList.Length; 
                    while (allocCount < resultCount)
                        allocCount *= 2; 
 
                    resultList = new Object[allocCount];
 
                    for (int i = 0; i < invocationCount; i++)
                        resultList[i] = invocationList[i];

                    if (followList == null) 
                    {
                        resultList[invocationCount] = dFollow; 
                    } 
                    else
                    { 
                        for (int i = 0; i < followCount; i++)
                            resultList[invocationCount + i] = followList[i];
                    }
                } 
                return NewMulticastDelegate(resultList, resultCount, true);
            } 
        }

리모브 () 방법의 밑바닥 실현 코드를 구체적으로 살펴보자. 리모브 All과 리모브 두 가지 방법은 시스템이다.Delegate 유형에서 CombineImpl 메서드는 MulticastDelegate에서 재작성됩니다.
public static Delegate RemoveAll(Delegate source, Delegate value) 
        {
            Delegate newDelegate = null; 

            do
            {
                newDelegate = source; 
                source = Remove(source, value);
            } 
            while (newDelegate != source); 

            return newDelegate; 
        }

 
[System.Security.SecuritySafeCritical] 
        protected override sealed Delegate RemoveImpl(Delegate value)
        {             MulticastDelegate v = value as MulticastDelegate; 

            if (v == null) 
                return this; 
            if (v._invocationList as Object[] == null)
            { 
                Object[] invocationList = _invocationList as Object[];
                if (invocationList == null)
                {
                    if (this.Equals(value))
                        return null; 
                } 
                else
                { 
                    int invocationCount = (int)_invocationCount;
                    for (int i = invocationCount; --i >= 0; )
                    {
                        if (value.Equals(invocationList[i])) 
                        {
                            if (invocationCount == 2) 
                            { 
                                return (Delegate)invocationList[1-i]; 
                            }
                            else
                            {
                                Object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, 1); 
                                return NewMulticastDelegate(list, invocationCount-1, true);
                            } 
                        } 
                    }
                } 
            }
            else
            {
                Object[] invocationList = _invocationList as Object[]; 
                if (invocationList != null) {
                    int invocationCount = (int)_invocationCount; 
                    int vInvocationCount = (int)v._invocationCount; 
                    for (int i = invocationCount - vInvocationCount; i >= 0; i--)
                    { 
                        if (EqualInvocationLists(invocationList, v._invocationList as Object[], i, vInvocationCount))
                        {
                            if (invocationCount - vInvocationCount == 0)
                            { 
                                return null; 
                            } 
                            else if (invocationCount - vInvocationCount == 1)
                            { 
                                return (Delegate)invocationList[i != 0 ? 0 : invocationCount-1];
                            }
                            else 
                            {
                                Object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, vInvocationCount); 
                                return NewMulticastDelegate(list, invocationCount - vInvocationCount, true); 
                            }
                        } 
                    }
                }
            }
 
            return this;
        }

 
[System.Security.SecuritySafeCritical] 
        public static Delegate Remove(Delegate source, Delegate value)
        {
            if (source == null) 
                return null;
 
            if (value == null) 
                return source;
 
            if (!InternalEqualTypes(source, value))
                throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis"));

            return source.RemoveImpl(value); 
        }

이상의 코드에서 우리는 알고 있다.NET 베이스는 어떻게 의뢰 실례의 귀속을 실현하고 삭제합니까?
위탁 실례를 호출할 때, 모든 조작은 순서대로 실행된다.만약void가 아닌 반환 형식을 호출한다면, 호출된 반환 값은 마지막 작업의 반환 값입니다.만약 호출 목록에서 어떤 조작이 이상을 던지면 후속 조작을 막을 것입니다.
위에서 언급한 위탁 목록에 비void 실례 호출이 나타나는데 위탁 실례에 여러 개의 비void 호출이 나타나고 모든 위탁 실례의 반환값 결과를 얻어야 한다면 어떻게 조작해야 하는가.NET 레드는 의뢰 체인 테이블을 가져오는 데 사용되는 GetInvocation List () 방법을 제공합니다.
GetInvocationList()의 기본 코드에 대해 자세히 살펴보겠습니다.
[System.Security.SecuritySafeCritical] 
        public override sealed Delegate[] GetInvocationList()
        {
            Delegate[] del;
            Object[] invocationList = _invocationList as Object[];
            if (invocationList == null)
            { 
                del = new Delegate[1];
                del[0] = this; 
            } 
            else
            { 
                int invocationCount = (int)_invocationCount;
                del = new Delegate[invocationCount]; 

                for (int i = 0; i < invocationCount; i++) 
                    del[i] = (Delegate)invocationList[i]; 
            }
            return del; 
        }

위탁 실례 목록을 얻은 후 순환 교체 방식으로 모든 위탁 실례의 반환 값을 순서대로 얻을 수 있다.
등록 정보 Method에 대해 자세히 살펴보고 이 등록 정보의 기본 구현 코드를 살펴보십시오.
public MethodInfo Method 
        {
            get
            {
                return GetMethodImpl(); 
            }
        } 
 
        [System.Security.SecuritySafeCritical] 
        protected virtual MethodInfo GetMethodImpl() 
        {
            if ((_methodBase == null) || !(_methodBase is MethodInfo))
            {
                IRuntimeMethodInfo method = FindMethodHandle(); 
                RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method);
                if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType)) 
                {
                    bool isStatic = (RuntimeMethodHandle.GetAttributes(method) & MethodAttributes.Static) != (MethodAttributes)0; 
                    if (!isStatic)
                    {
                        if (_methodPtrAux == (IntPtr)0)
                        { 
                            Type currentType = _target.GetType(); 
                            Type targetType = declaringType.GetGenericTypeDefinition(); 
                            while (currentType != null)
                            { 
                                if (currentType.IsGenericType &&
                                    currentType.GetGenericTypeDefinition() == targetType)
                                {
                                    declaringType = currentType as RuntimeType; 
                                    break;
                                } 
                                currentType = currentType.BaseType; 
                            }

                            BCLDebug.Assert(currentType != null || _target.GetType().IsCOMObject, "The class hierarchy should declare the method"); 
                        }
                        else 
                        { 
                            MethodInfo invoke = this.GetType().GetMethod("Invoke"); 
                            declaringType = (RuntimeType)invoke.GetParameters()[0].ParameterType;
                        }
                    }
                } 
                _methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method);
            } 
            return (MethodInfo)_methodBase; 
        }

지금까지 시스템이었습니다.Delegate 클래스의 정의는 다음과 같습니다. MulticastDelegate 다시 쓰기:
[System.Security.SecuritySafeCritical] 
        protected override MethodInfo GetMethodImpl()
        { 
            if (_invocationCount != (IntPtr)0 && _invocationList != null) 
            {
                Object[] invocationList = _invocationList as Object[];
                if (invocationList != null)
                {
                    int index = (int)_invocationCount - 1; 
                    return ((Delegate)invocationList[index]).Method;
                } 
                MulticastDelegate innerDelegate = _invocationList as MulticastDelegate; 
                if (innerDelegate != null)
                { 
                    return innerDelegate.GetMethodImpl();
                }
            } 
            else if (IsUnmanagedFunctionPtr())
            { 
                if ((_methodBase == null) || !(_methodBase is MethodInfo)) 
                {
                    IRuntimeMethodInfo method = FindMethodHandle();
                    RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method);
                    if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType)) 
                    { 
                        RuntimeType reflectedType = GetType() as RuntimeType; 
                        declaringType = reflectedType;
                    }
                    _methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method);
                } 
                return (MethodInfo)_methodBase;
            } 
            return base.GetMethodImpl(); 
        }

이상은 위탁에 대한 정의와 위탁에 대한 조작 방법에 대한 설명으로 위탁을 어떻게 창설하고 사용하는지 구체적으로 밝히지 않았다. 위탁의 간단한 창설과 일반 응용 때문에 대부분의 개발자에게 비교적 간단하다. 왜냐하면 마이크로소프트는 C#의 문법을 끊임없이 향상시키고 수정하기 때문에 대응하는 조작을 크게 간소화했다.그러나 응용층에 비교적 큰 봉인을 했기 때문에 특성이 밑바닥의 복잡도가 점점 커질 수 있다.

좋은 웹페이지 즐겨찾기