静态方法依赖于子类?

时间:2016-03-23 19:50:45

标签: c# abstract-class

如何使静态方法的行为依赖于它调用的类? E.g。

abstract class Base
{
    public static string GetClassName()
    { ???? }
}
class A : Base { }
class B : Base { }

static void Main(string[] args)
{
    Console.WriteLine(A.GetClassName()); // Want to print "A"
    Console.WriteLine(B.GetClassName()); // Want to print "B"
}

请注意,如果我在MethodBase.GetCurrentMethod().DeclaringType.Name中使用Base.GetClassName,则会返回“Base”。

另请注意,这与其他几个SO问题类似,如下所示,但我要以更简洁的方式询问它,以便记录除“你不能”之外的答案:

1 个答案:

答案 0 :(得分:0)

关键是要添加一个类型参数:

abstract class Base<T>
    where T : Base<T>
{
    public static string GetClassName()
    {
        return typeof(T).Name;
    }
}

class A : Base<A> { }

class B : Base<B> { }

这会使Base的静态成员属于特定的类Base<T>,无论T是什么。因此,不再使用单个Base.GetClassName方法,但在这种情况下,现在有两种方法:Base<A>.GetClassNameBase<B>.GetClassName。此外,对type参数的约束使得class B : Base<A>成为不可能,这可以保证A.GetClassNameB.GetClassName将返回不同的内容。

特定于子类的行为可以进一步扩展:

abstract class Base<T>
where T : Base<T>
{
    private static HashSet<string> values = new HashSet<string>();

    internal Base(string value)
    {
        if (Base<T>.values.Contains(value))
            throw new Exception("Not unique");
        else
            Base<T>.values.Add(value);
    }

    public static string GetClassName()
    {
        return typeof(T).Name;
    }

    public static IEnumerable<string> GetValues()
    {
        return new LinkedList<string>(Base<T>.values);
    }
}

class A : Base<A>
{
    public A(string value) : base(value) { }
}

class B : Base<B>
{
    public B(string value) : base(value) { }
}

static void Main(string[] args)
{
    var a1 = new A("value");
    var a2 = new A("value 2");
    // var a3 = new A("value"); // Would throw an exception
    var b = new B("value"); // Does not throw an exception

    Console.WriteLine(A.GetClassName()); // Prints "A"
    Console.WriteLine(B.GetClassName()); // Prints "B"

    Console.WriteLine("The values in A:");
    foreach (var value in A.GetValues()) // This loop prints "value" and "value 2"
    {
        Console.WriteLine("\t" + value);
    }
    Console.WriteLine("The values in B:");
    foreach (var value in B.GetValues()) // This loop prints "value"
    {
        Console.WriteLine("\t" + value);
    }
}

在这种情况下,values / Base<A>A / Base<B>中有不同的静态B对象。

然而,所有这些都需要付出代价。在上面的例子中,Base的子类不可能访问相同的静态对象而没有所有子类知道彼此先验。例如。 B无法访问与values相同的A对象。一种可能的解决方法是在希望所有子类共享值时使用Base<agreed-upon-type>.values