ホームページ >バックエンド開発 >C#.Net チュートリアル >その裏話 - Happy Lambda Expression (2)

その裏話 - Happy Lambda Expression (2)

黄舟
黄舟オリジナル
2017-02-16 10:52:241463ブラウズ

前回の記事 – 幸せなラムダ式 (1) ラムダ式を浅いところから深いところまで分析しました。デリゲートや通常のメソッドとの違いを理解し、テストを通じてパフォーマンスを比較します。次に、IL コードを通じてラムダ式を深く理解し、.NET でラムダ式を使用して一般的な JavaScript のいくつかのパターンを実装する方法を紹介します。 。

今日は、.NET でラムダ式を使用する他の新しい方法を見てみましょう。

Lambda 式でポリモーフィズムを試してみる

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 を使用して上書きを実現すると同時に、previousActions に元のメソッドを保存します。こうすることで、両方を同時に存在させることができます。

サブクラスが親クラスの静的メソッドをオーバーライドできないことは誰もが知っていますが、静的メソッドのカバレッジを実装したい場合はどうすればよいでしょうか?

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

ここでも、ラムダ式が属性として使用され、いつでも再割り当てできるという事実を利用しています。もちろん、これは単なる例であり、実際のプロジェクトでこれを行うことはすべての人に推奨されません。

メソッド辞書

実は、このモードについては前回の記事の return メソッドで既に説明しましたが、そのような名前はないので、単なる概要です。ストーリーは次のようなものですが、switch-case ステートメントを作成するときに、エレガントさが足りないと感じることがよくありますか?しかし、ファクトリー モードやストラテジー モード全体には入りたくないので、コードをより高度に見せるにはどうすればよいでしょうか?

rreee

ちょっとした味付けで見た目も違うようです。しかし、よく考えてみると、すべてのメソッドを BuildFinalizers に入れる必要があるのですが、この編成方法は本当に受け入れられません。プラグインの開発方法を学び、必要なメソッドをすべて独自に見つけてもらいましょう。

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 中国語 Web サイト (www.php.cn) をご覧ください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。