이전 글 그 비하인드 스토리 - 해피 람다 표현 (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)를 주목해주세요!