各派生クラスを強制的に Singleton にする抽象クラスを作成するにはどうすればよいですか? 私はC#を使用しています。
7 に答える
シングルトンには静的アクセスが必要であり、強制できないため、これは機能しません。
シングルトンの実装と例については、「 C#でのシングルトンパターンの実装」を参照してください。
コンパイル時のチェックを有効にしたい場合、これは不可能です。実行時チェックを使用すると、これを行うことができます。きれいではありませんが、可能です。次に例を示します。
public abstract class Singleton
{
private static readonly object locker = new object();
private static HashSet<object> registeredTypes = new HashSet<object>();
protected Singleton()
{
lock (locker)
{
if (registeredTypes.Contains(this.GetType()))
{
throw new InvalidOperationException(
"Only one instance can ever be registered.");
}
registeredTypes.Add(this.GetType());
}
}
}
public class Repository : Singleton
{
public static readonly Repository Instance = new Repository();
private Repository()
{
}
}
シングルトンとは、プライベート コンストラクターを持つことを意味します。しかし、プライベート メンバーは継承できないことがわかっています。C++ にはテンプレートがあったため、テンプレート クラスからシングルトンを作成できました。C# にはテンプレートがないため、必要なシングルトンごとに独自のプライベート コンストラクターを作成する必要があります。
Java または C# のクラスは「ファーストクラス」ではありません。クラスの静的部分は、サブクラスによって継承またはオーバーライドできません。詳細については、この回答を参照してください。さらに、メタクラスの概念がありません。
Smalltalk や Ruby などの言語Singleton
では、メソッドを定義する新しいメタクラスを定義できますgetInstance
。次に、メタクラスを定義ClassA
しClassB
てインスタンスにすることができます。Singleton
次に、両方のクラスが、インスタンスまたはgetInstance
の作成に使用できるメソッドを自動的に公開します。かっこよくない?実際には、メタクラスを頻繁に使用することはありません。シングルトンは、実際には意味があり、私が認識している唯一の使用法です。objectA
objectB
ここで、Singleton 継承の実装を示します。
using System;
using System.Reflection;
namespace Mik.Singleton
{
class Program
{
static void Main()
{
//You can not create an instance of class directly
//Singleton1 singleton1 = new Singleton1();
Singleton1 singleton1 = Singleton1.Instance;
Singleton2 singleton2 = Singleton2.Instance;
Console.WriteLine(singleton1.Singleton1Text);
Console.WriteLine(singleton2.Singleton2Text);
Console.ReadLine();
}
}
public class SingletonBase<T> where T : class
{
#region Singleton implementation
private static readonly object lockObj = new object();
private static T _instance;
protected SingletonBase() { }
public static T Instance
{
get
{
if (_instance == null)
{
lock (lockObj)
{
if (_instance == null)
_instance = CreateInstance();
}
}
return _instance;
}
}
private static T CreateInstance()
{
ConstructorInfo constructor = typeof(T).GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
null, new Type[0],
new ParameterModifier[0]);
if (constructor == null)
throw new Exception(
$"Target type is missing private or protected no-args constructor: {typeof(T).FullName}");
try
{
T instance = constructor.Invoke(new object[0]) as T;
return instance;
}
catch (Exception e)
{
throw new Exception(
"Failed to create target: type=" + typeof(T).FullName, e);
}
}
#endregion Singleton implementation
}
public class Singleton1 : SingletonBase<Singleton1>
{
private Singleton1() { }
public string Singleton1Text { get; } = "Singleton1Text value";
}
public class Singleton2 : SingletonBase<Singleton2>
{
private Singleton2() { }
public string Singleton2Text { get; } = "Singleton2Text value";
}
}