【问题标题】:How to create a lazy singleton aspect with PostSharp?如何使用 PostSharp 创建一个惰性单例方面?
【发布时间】:2018-08-21 19:17:59
【问题描述】:
假设具有私有构造函数的密封类的以下单例声明:
private static readonly Lazy<MyClass> _singleton = new Lazy<MyClass>(() => new MyClass());
public static MyClass Instance => _singleton.Value;
有没有办法创建一个 PostSharp 方面,允许我向 Instance 属性添加一个属性 (PsSingleton):
[PsSingleton]
public static MyClass Instance {get; set;}
让这个类在运行时变成一个惰性单例?
【问题讨论】:
标签:
c#
singleton
postsharp
aspect
【解决方案1】:
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();
}
}
}