反转旋木

反转旋木

时代的一粒尘埃,落在个人身上就是一座大山

遇到有趣的コード-リフレクションでコンポーネントを取得する

之前、Unity のコンポーネントを取得する方法をよく見かけましたが、ずっと使っていて背後の秘密を知りませんでした。これはメモ帳に書かれた使い方です。今日はなぜか気分が乗らないし、退屈しているので、この背後の原理を知りたいと思います。

    [UIControl("normal/Back/Title/Text")]
    protected Text TitleText;

探索フェーズ 1#

まず、実装方法を見つけます。

public class UIControlAttribute : Attribute
{
    public string controlName;
    public System.Type componentType;
    public int baseNum;
    public UIControlAttribute(string controlName,System.Type componentType = null,int baseNum = 0)
    {
        this.controlName = controlName;
        this.componentType = componentType;
        this.baseNum = baseNum;
    }
}

最初の印象は、C# の属性を継承しているようです。

それでは、これはどのようにして取得されるのでしょうか?当時はまったくわかりませんでした。

おそらく C# の属性についてもう少し理解する必要があるようです。

探索フェーズ 2#

この先生の紹介を見ると、かなり具体的でわかりやすいです。簡単に言えば、属性は「付着物」のようなものです - 船底や岩に付着するカキのようなものです。

Attribute は、ユーザーが独自に定義できる修飾子(Modifier)であり、さまざまな対象を修飾するために使用できます。クラスや C# プログラムのアセンブリのメンバーをさらに説明することができます。

Python のデコレーターに似ていますが、クラスやメソッドに対して再度説明を行うためのものです。

コメントとの本質的な違いは、破棄されないことです#

Attribute はプログラムコードの一部であり、コンパイラによって破棄されることはなく、プログラムアセンブリ(Assembly)のメタデータ(Metadata)にコンパイラによってコンパイルされます。プログラムが実行されるとき、いつでもメタデータからこれらの追加情報を抽出し、プログラムの実行を決定するために使用できます。

以下は、上記の先生が提供した簡単な例です#

たとえば、人のクラス Person を書くことを考えます。このクラスは、人の属性や特定の行動(メソッド)について説明することができます。では、人クラスをさらに説明する必要がある場合はどうでしょうか?たとえば、人クラスは霊長類の動物の一部であると言えます。もちろん、人は人クラスを親クラスとして霊長類クラスを作成し、人クラスを継承することでこれを解決することができます。しかし、私たちが求めているのは単に記述的なものであり、実際の操作は必要ありません。このような場合、属性の概念を使用して問題を解決することができます。属性は、プログラムアセンブリの特定のプログラム要素が持つ追加の特性です。

		//まず、人クラスを定義します
        class Person
        {
            //人の名前のフィールドとプロパティ
            private string name;
            public string Name
            {
                set { name = value; }
                get { return name; }
            }

            //人の年齢のフィールドとプロパティ
            private int age;
            public int Age
            {
                set { age = value; }
                get { return age; }
            }

            //人の性別のフィールドとプロパティ
            private char sex;
            public char Sex
            {
                set { sex = value; }
                get { return sex; }
            }

            //人の挨拶メソッド
            public void SayHello()
            {
                Console.WriteLine($"こんにちは、私の名前は{this.Name}です。今年{this.Age}歳で、性別は{this.Sex}です。");
            }
        }

次に、霊長類の特徴を定義します。

        //動物の特性クラスAnimalAttributeクラスはAttribute(属性)を継承します
        class AnimalAttribute : Attribute
        {
            //フィールドとプロパティは霊長類であるかどうかを説明します
            private bool isPrimate;
            public bool IsPrimate
            {
                set { isPrimate = value; }
                get { return isPrimate; }
            }
        }

人クラスに動物クラスの特性を追加します。つまり、人クラスの定義の前に次のように書きます。

[Animal (IsPrimate = true)]  // 人クラスに特性を追加し、人クラスが霊長類であることを指定します。

[Animal(IsPrimate = true)] 
class Person

その後、リフレクションを使用して特性を取得できます。

//特性オブジェクトを宣言し、Attributeクラスの静的メソッドGetCustomAttribute()を使用して人クラスの動物クラスの特性を取得し、特性オブジェクトに割り当てます
            Attribute att1 = Attribute.GetCustomAttribute(typeof(Person), typeof(AnimalAttribute));

            //特性オブジェクトを動物特性オブジェクトに変換します
            AnimalAttribute animalAtt = att1 as AnimalAttribute;

            //変換が成功したかどうかをチェックし、成功した場合はこの特性オブジェクトのIsPrimateプロパティを出力します
            if (animalAtt != null)
            {
                Console.WriteLine("人クラスは霊長類ですか?:{0}", animalAtt.IsPrimate);
            }
            Console.ReadKey();

応用#

以前に文字列を大文字に変換するメソッドを作成する必要があったのですが、これを使用して簡単に調整できます。

お手数ですが、GPT にコードを書いてもらえますか?

using System;
using PostSharp.Aspects;

[Serializable]
public class ToUpperCaseAttribute : MethodInterceptionAspect
{
    public override void OnSuccess(MethodExecutionArgs args)
    {
        if (args.ReturnValue is string returnValue)
        {
            args.ReturnValue = returnValue.ToUpper();
        }
    }
}

public class MyClass
{
    [ToUpperCase]
    public string GetUpperCaseString(string input)
    {
        return input;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var myClass = new MyClass();
        string result = myClass.GetUpperCaseString("Hello, World!");
        Console.WriteLine(result); // 出力は "HELLO, WORLD!" になります
    }
}

MethodInterceptionAspect は、メソッドの実行のさまざまな段階でカスタムコードを挿入することを可能にします。

OnSuccess メソッド: OnSuccess は、メソッドが正常に完了した後に呼び出されるメソッドです。このメソッドでは、メソッドの戻り値にアクセスして操作することができます。上記の例では、OnSuccess メソッドを使用してメソッドの戻り値である文字列を大文字に変換しています。

探索フェーズ 3#

原理を知った後、パネルコントロールの初期化に関する情報を検索しました。

image-20230812141447825

UI に関する操作があります。疑問が解消されました。

この記事は Mix Space から xLog に同期されています。
元のリンクは http://121.41.123.51:2333/posts/categories/3 です。


読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。