如何使用 PostSharp 创建惰性单例方面?

How to create a lazy singleton aspect with PostSharp?

假设密封 class 具有私有构造函数的以下单例声明:

private static readonly Lazy<MyClass> _singleton = new Lazy<MyClass>(() => new MyClass());
public static MyClass Instance => _singleton.Value;

有没有一种方法可以创建 PostSharp 方面,允许我将属性 (PsSingleton) 添加到 Instance 属性 中:

[PsSingleton]
public static MyClass Instance {get; set;}

并让 class 在 运行 时变成懒惰的单身人士?

using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;
using System;
using System.Reflection;

namespace LazySingletonSample
{
    class Program
    {
        static void Main(string[] args)
        {
            TestClass.Instance.SayHello();
            TestClass.Instance.SayHello();
            TestClass.Instance.SayHello();
        }
    }

    public class TestClass
    {
        [LazySingleton]
        public static TestClass Instance;

        public void SayHello()
        {
            Console.WriteLine("Hello from singleton!");
        }
    }

    // TODO: Restrict usage
    [PSerializable]
    public sealed class LazySingletonAttribute : LocationInterceptionAspect
    {
        object singletonInstance;
        ConstructorInfo constructor;

        public override bool CompileTimeValidate(LocationInfo locationInfo)
        {
            // TODO: check that:
            // - field name is "Instance"
            // - field type is the same as the declaring type
            // - there is only a default constructor
            // - the constructor is private
            // - the constructor is not called anywhere
            // - the field is not set anywhere

            return true;
        }

        public override void CompileTimeInitialize(LocationInfo targetLocation, AspectInfo aspectInfo)
        {
            this.constructor = targetLocation.DeclaringType.GetConstructor(new Type[] { });
        }

        public override void OnGetValue(LocationInterceptionArgs args)
        {
            if (this.singletonInstance == null)
            {
                Console.WriteLine("Creating singleton instance.");
                this.singletonInstance = constructor.Invoke(new object[] { });
            }

            Console.WriteLine("Returning singleton instance.");
            args.Value = this.singletonInstance;
        }

        public override void OnSetValue(LocationInterceptionArgs args)
        {
            throw new InvalidOperationException();
        }
    }
}