2016-03-23 137 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