2016-03-23 97 views
-1

我怎样才能使一个静态方法的行为依赖于它所调用的类? 例如依赖于子类的静态方法?

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" 
} 

需要注意的是,如果我在Base.GetClassName使用MethodBase.GetCurrentMethod().DeclaringType.Name,那么 “基地” 返回。

另外请注意,这是类似于其他几个SO问题,比如下面的,但为了证明不是“你不能”以外的回答,我要求它更简洁的方式:

+1

[C#虚拟(或抽象)静态方法]的可能重复(http://stackoverflow.com/questions/763344/c-sharp-virtual-or-abstract-static-methods) –

+0

@JasonWatkins。感谢标记为dup。每个http://meta.stackoverflow.com/questions/314210/should-i-ask-a-new-question-in-order-to-make-the-answer-easier-to-find我应该做到这一点 –

回答

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<A>.GetClassNameBase<B>.GetClassName。此外,对类型参数的约束使得不可能有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); 
    } 
} 

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

但是,所有这些都带来了成本。在上面的例子中,子类Base不可能访问相同的静态对象,而所有的子类都不知道对方先验。例如。 B无法访问与A相同的values对象。当您希望所有子类共享值时,一种可能的解决方法是使用Base<agreed-upon-type>.values