>  기사  >  백엔드 개발  >  그 비하인드 스토리 - Happy Lambda Expression (2)

그 비하인드 스토리 - Happy Lambda Expression (2)

黄舟
黄舟원래의
2017-02-16 10:52:241436검색

이전 글 그 비하인드 스토리 - 해피 람다 표현 (1) 람다 표현을 얕은 것부터 깊은 것까지 분석해봤습니다. 대리자 및 일반 메서드와의 차이점을 알고 테스트를 통해 성능을 비교한 다음 IL 코드를 통해 Lambda 식을 심층적으로 이해하고 .NET에서 Lambda 식을 사용하여 인기 있는 JavaScript 패턴을 구현하는 방법을 소개했습니다. .

오늘은 .NET에서 Lambda 표현식을 사용하는 다른 새로운 방법을 살펴보겠습니다.

다형성을 활용하는 람다 표현식

람다는 다형성을 어떻게 구현합니까? 우리는 추상 클래스와 가상 메서드를 사용하는데 왜 여전히 Lambda를 사용합니까? 다음 코드를 살펴보겠습니다.

class MyBaseClass
{
    public Action SomeAction { get; protected set; }
 
    public MyBaseClass()
    {
        SomeAction = () =>
        {
            //Do something!
        };
    }
}
 
class MyInheritedClass : MyBaseClass
{
    public MyInheritedClass()
    {
        SomeAction = () => {
            //Do something different!
        };
    }
}

기본 클래스는 추상 클래스가 아니며 가상 메서드도 없지만 위임을 통해 속성을 노출한 다음 하위 클래스의 SomeAction에 새 속성을 다시 할당합니다. . 표현. 이것은 다형성을 실현하는 과정입니다. 물론 부모 클래스의 SomeAction 집합에는 보호 수준이 있습니다. 그렇지 않으면 외부에서 쉽게 수정할 수 있습니다. 그러나 이는 아직 완벽하지 않습니다. 상위 클래스의 SomeAction을 하위 클래스에서 덮어쓴 후에는 전혀 액세스할 수 없습니다. 실제 상황은 base를 통해 상위 클래스의 원래 메서드에 액세스할 수 있다는 것입니다. 다음 단계는 이

class MyBaseClass
{
    public Action SomeAction { get; private set; }
 
    Stack<Action> previousActions;
 
    protected void AddSomeAction(Action newMethod)
    {
        previousActions.Push(SomeAction);
        SomeAction = newMethod;
    }
 
    protected void RemoveSomeAction()
    {
        if(previousActions.Count == 0)
            return;
 
        SomeAction = previousActions.Pop();
    }
 
    public MyBaseClass()
    {
        previousActions = new Stack<Action>();
 
        SomeAction = () => {
            //Do something!
        };
    }
}

를 구현하는 것입니다. 위 코드에서는 AddSomeAction을 사용하여 덮어쓰기를 수행하는 동시에 이전 메서드에 원래 메서드를 저장합니다. 이런 식으로 우리는 동시에 두 가지를 모두 유지할 수 있습니다.

하위 클래스가 상위 클래스의 정적 메서드를 재정의할 수 없다는 것은 누구나 알고 있지만 정적 메서드 적용 범위를 구현하려면 어떻게 해야 할까요?

void Main()
{
    var mother = HotDaughter.Activator().Message;
    //mother = "I am the mother"
    var create = new HotDaughter();
    var daughter = HotDaughter.Activator().Message;
    //daughter = "I am the daughter"
}
 
class CoolMother
{
    public static Func<CoolMother> Activator { get; protected set; }
 
    //We are only doing this to avoid NULL references!
    static CoolMother()
    {
        Activator = () => new CoolMother();
    }
 
    public CoolMother()
    {
        //Message of every mother
        Message = "I am the mother";
    }
 
    public string Message { get; protected set; }
}
 
class HotDaughter : CoolMother
{
    public HotDaughter()
    {
        //Once this constructor has been "touched" we set the Activator ...
        Activator = () => new HotDaughter();
        //Message of every daughter
        Message = "I am the daughter";
    }
}

여기에서도 람다 표현식이 속성으로 사용되고 언제든지 재할당될 수 있다는 점을 활용합니다. 물론 이는 단순한 예일 뿐이며 모든 사람이 실제 프로젝트에서 이 작업을 수행하는 것은 권장되지 않습니다.

방법 사전

사실 이 모드는 이전 글의 반환 방법에서 이미 언급한 바 있지만, 그런 이름이 없어서 간단히 요약한 것입니다. 이야기는 이렇습니다. switch-case 문을 작성할 때 우아하지 않다고 느끼는 경우가 자주 있습니까? 하지만 전체 팩토리 모드나 전략 모드로 들어가고 싶지 않다면 어떻게 코드를 더욱 고급스러워 보이게 만들 수 있을까요?

으으으으

보기에도 좀 다른 것 같고, 맛도 좀 있는 것 같아요. 그런데 생각해보면 모든 메소드를 BuildFinalizer에 넣어야 하는데 이런 구성 방식은 정말 용납할 수 없는 플러그인 개발 방식을 배워서 스스로 필요한 메소드를 모두 찾도록 해보자.

public Action GetFinalizer(string input)
{
    switch
    {
        case "random":
            return () => { /* ... */ };
        case "dynamic":
            return () => { /* ... */ };
        default:
            return () => { /* ... */ };
    }
}
 
//-------------------变身之后-----------------------
Dictionary<string, Action> finalizers;
 
public void BuildFinalizers()
{
    finalizers = new Dictionary<string, Action>();
    finalizers.Add("random", () => { /* ... */ });
    finalizers.Add("dynamic", () => { /* ... */ });
}
 
public Action GetFinalizer(string input)
{
    if(finalizers.ContainsKey(input))
        return finalizers[input];
 
    return () => { /* ... */ };
}

플러그인을 구현하려면 이 어셈블리에 메서드를 로드할 수 있을 뿐만 아니라 언제든지 또는 런타임 중에도 외부 메서드를 로드할 수 있어야 합니다.

static Dictionary<string, Action> finalizers;
 
// 在静态的构造函数用调用这个方法
public static void BuildFinalizers()
{
    finalizers = new Dictionary<string, Action>();
 
    // 获得当前运行程序集下所有的类型
    var types = Assembly.GetExecutingAssembly().GetTypes();
 
    foreach(var type in types)
    {
        // 检查类型,我们可以提前定义接口或抽象类
        if(type.IsSubclassOf(typeof(MyMotherClass)))
        {
            // 获得默认无参构造函数
            var m = type.GetConstructor(Type.EmptyTypes);
 
            // 调用这个默认的无参构造函数
            if(m != null)
            {
                var instance = m.Invoke(null) as MyMotherClass;
                var name = type.Name.Remove("Mother");
                var method = instance.MyMethod;
                finalizers.Add(name, method);
            }
        }
    }
}
 
public Action GetFinalizer(string input)
{
    if(finalizers.ContainsKey(input))
        return finalizers[input];
 
    return () => { /* ... */ };
}

이제 이 방법을 사용하여 필요한 것을 로드할 어셈블리를 지정할 수 있습니다.

마지막으로 질문 남깁니다. 재귀 표현식을 작성할 수 있나요? 표현식을 사용하여 다음 메소드를 작성하는 방법은 무엇입니까?

internal static void BuildInitialFinalizers()
{
    finalizers = new Dictionary<string, Action>();
    LoadPlugin(Assembly.GetExecutingAssembly());
}
 
public static void LoadPlugin(Assembly assembly)
{
    var types = assembly.GetTypes();
    foreach(var type in types)
    {
        if(type.IsSubclassOf(typeof(MyMotherClass)))
        {
            var m = type.GetConstructor(Type.EmptyTypes);
 
            if(m != null)
            {
                var instance = m.Invoke(null) as MyMotherClass;
                var name = type.Name.Remove("Mother");
                var method = instance.MyMethod;
                finalizers.Add(name, method);
            }
        }
    }
}

위 내용은 Happy Lambda Expression(2)의 비하인드 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 주목해주세요!


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