单身人士,通用&继承 - 让所有子类继承单例功能

时间:2013-11-15 22:00:20

标签: c# generics singleton

我有两个问题。一个是我正在尝试一个抽象的单例类,它具有单例功能+一些额外的功能,但这个类也是通用的(与单例无关)。我希望它的任何子类都能在不重写代码的情况下继承单例功能,还需要依赖于泛型类型的其余功能。

第二个问题,抽象类有一个非默认的构造函数,它应该接收一个字符串值。该字符串可以由子类的类(继承抽象calss的类)确定。

我的想法如下处理:

  • 将抽象静态方法添加到返回字符串参数的抽象类中,以便每个派生类都将实现它,因此该类的任何非抽象实例都可以正常工作。不可能,因为静态方法不能是抽象的。
  • 使用返回字符串的静态方法创建接口,并确保泛型类型继承自该接口。然后在实例化单例时,它将调用T.GetTheString()作为参数传递给构造函数。不可能,因为接口可能没有静态方法。

有什么想法吗?

以下是一些解释我问题的简化代码:

public abstract class NamedObject<T> {
    private static NamedObject<T> _instance;
    public static NamedObject<T> Instance {
        get {
            if (_instance == null) {
                _instance = new NamedObject<T>("Need to determine this string from the non-abstract child class of NamedObject");
            }
            return _instance;
        }
    }

    private string objectName;

    public NamedObject(string objectName) {
        this.objectName = objectName;
    }

    public string GetFullName() {
        return objectName + "(" + GetClassName() + ")";
    }

    protected virtual string GetClassName() {
        return typeof(T).ToString();
    }
}

请注意,我需要GetClassName()的泛型T,并注意要创建单例的实例,我需要调用继承此类的子类的静态方法(这似乎是不可能的)

编辑:更新了问题以更好地反映我的问题。


编辑:感谢大家的帮助。第二个问题的解决方案是使用默认构造函数,并从子类的非静态方法(基类中的抽象)中获取构造函数中应该是参数的字符串。

另外,我对Singleton继承的整个想法都是错误的,由于Rob Lyndon的回答,我设法解决了这个问题。

这是最终的代码(我知道它没有意义,这只是一个简化的版本......):

public abstract class NamedObject<ME, T> where ME : NamedObject<ME, T>, new()
{
    private static NamedObject<ME, T> _instance;
    public static NamedObject<ME, T> Instance {
        get {
            if (_instance == null) {
                _instance = new ME();
            }
            return _instance;
        }
    }

    private string objectName = "test";

    public NamedObject() {
        this.objectName = GetObjectName();
    }

    public string GetFullName() {
        return objectName + "(" + GetClassName() + ")";
    }

    protected virtual string GetClassName() {
        return typeof(T).ToString();
    }

    protected abstract string GetObjectName();
}

孩子班:

public sealed class MyNamedObject : NamedObject<MyNamedObject, MyClass>
{
    public MyNamedObject() : base() {
    }

    protected override string GetObjectName () {
        return "MyName";
    }
}

因此,第一次调用MyNamedObject.Instance时,它将NamedObject()构造函数,MyClassTobjectName参数将为{{} 1}}由子类"MyName"定义。

正是我在寻找的东西。感谢大家的帮助,这非常有帮助。

3 个答案:

答案 0 :(得分:2)

我建议你介绍一个用你装饰每种类型的属性,并在需要时提取它。您将无法在编译时验证类型具有正确的类型,但是您无法做很多事情。单元测试您需要的所有类型:)

[AttributeUsage(AttributeTargets.Class)]
public class NameAttribute : Attribute
{
    public NameAttribute(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }
}

[Name("Foo")]
public class SomeClass
{
}

然后在你的单例类中,使用静态构造函数而不是线程不安全的属性。

private static readonly NamedObject<T> instance;

static NamedObject()
{
    // TODO: Validation :)
    var attributes = typeof(T).GetCustomAttributes(typeof(NameAttribute), false);
    var firstAttribute = ((NameAttribute[]) attributes)[0];
    string name = firstAttribute.Name;
    instance = new NamedObject<T>(name);
}

public static NamedObject<T> Instance { get { return instance; } }

或者使用Lazy<>代替。有关这方面的更多信息,请参阅my article on singletons

编辑:澄清 - 你不应该将NamedObject作为抽象类开始。单身人士和继承根本就不混合NamedObject<T>应该是一个密封的类,它具有任何T的单个实例。它并不强制只创建了T的一个实例。

答案 1 :(得分:2)

不要做单身人士。如初。

无论如何,这是一种接近你的用例的方法。

// base class
public abstract class NamedObject<ME, T> where ME : NamedObject<ME, T>, new()
{
    private static NamedObject<ME, T> _instance;
    public static NamedObject<ME, T> Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new ME { objectName = GetLabel(typeof(T)) };
            }
            return _instance;
        }
    }

    private string objectName;

    public string GetFullName()
    {
        return objectName + "(" + GetClassName() + ")";
    }

    protected abstract string GetLabel(Type type);
    protected abstract string GetClassName();
}

答案 2 :(得分:0)

这应该做你想要的(Name属性也可以是一个抽象方法,如果我们使用单例模式,它看起来更好。)

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(MyNamedObject.Instance.Name);
    }
}

public abstract class NamedObject<T> where T : NamedObject<T>, new()
{
    private static T _instance;

    public abstract string Name { get; }

    public static T Instance
    {
        get { return _instance ?? (_instance = new T()); }
    }
}

public class MyNamedObject : NamedObject<MyNamedObject>
{
    public override string Name
    {
        get { return "My Named Object Name"; }
    }
}