2017-02-20 151 views
3

Im上的靜態方法調用上使用 Im遵循 this示例的泛型類。 因爲我不想用測試代碼填充我的項目的主要功能,我想創建一個運行代碼示例的靜態展示函數。 爲什麼我必須在通用類

我的代碼:

namespace Syntax 
{ 
    public class GenericClass<T> 
    { 
     private class Node 
     { 
      private T data; 
      private Node next; 

      public Node(T t) 
      { 
       next = null; 
       data = t; 
      } 

      public Node Next { get { return next; } set { next = value; } } 
      public T Data { get { return data; } set { data = value; } } 
     } 


     private Node head; 
     public GenericClass() 
     { 
      head = null; 
     } 

     public void AddHead(T t) 
     { 
      Node n = new Node(t); 
      n.Next = head; 
      head = n; 
     } 

     public IEnumerator<T> GetEnumerator() 
     { 
      Node current = head; 
      while (current != null) 
      { 
       yield return current.Data; 
       current = current.Next; 
      } 
     } 


     public static void Showcase() 
     { 
      GenericClass<int> list = new GenericClass<int>(); 

      for(int x = 0; x <10; x++) 
      { 
       list.AddHead(x); 
      } 

      System.Console.WriteLine("\nPrinting generic class using ints."); 
      foreach (int i in list) 
      { 
       System.Console.Write(i + ", "); 
      } 

      GenericClass<char> listChars = new GenericClass<char>(); 
      string abc = "abcdefghijklmnopqrstuvw"; 
      foreach (char c in abc) 
      { 
       listChars.AddHead(c); 
      } 

      System.Console.WriteLine("\n\nPrinting generic class using chars."); 
      foreach (var c in listChars) 
      { 
       System.Console.Write(c + ", "); 
      } 
     } 
    } 
} 

這幾乎完全一樣,除了靜態展示方法鏈接的例子。

現在在我的主要方法我可以打電話:

GenericClass<int>.Showcase(); 

我可以改變代碼:

GenericClass<string>.Showcase(); 
GenericClass<char>.Showcase(); 

它仍然能工作。

如果我能做到

GenericClass<int> test = new GenericClass<int>(); 
test.Showcase(); 

它將使總感覺,我認爲這將需要一個類型,因爲我可以呼籲其他測試方法。

我沒有看到添加類型的優點,需要添加一個隨機類只會導致我腦海中的混亂,爲什麼不是靜態方法的語法genericClass<T>.StaticMethod();例如將一個類型添加到靜態方法dosnt add anythig(或者是否?)。那麼爲什麼在調用泛型類的靜態方法時需要使用<T>

回答

5

由於您尚未創建名爲GenericClass的類,因此您已創建一個名爲GenericClass<T>的開放式泛型類。

沒有什麼可以阻止你在相同的命名空間創建類GenericClass,也沒有什麼可以阻止你創建一個名爲GenericClass<T1,T2>的類。所有這些都可以存在於同一個命名空間中,除非你聲明一個,否則它們之間沒有明確或隱含的關係。因此,如果你想調用一個靜態方法在「在一個類型參數中通用的GenericClass類」上,你必須說,不知何故,你已經找到了如何做到這一點 - 通過提供一個類型參數。

有人可能會爭辯說,如果靜態方法不使用類型參數,它是多餘的 - 那麼爲什麼你不能僅僅通過使用仍然打開的類型參數來調用它呢?那麼,首先是因爲那必須是新的語法來允許這種情況發生。其次,如果你的方法訪問任何靜態字段會發生什麼?對於泛型類型,用作類型參數的每個唯一類型都會導致一組新的靜態字段存在。


爲什麼心不是語法的靜態方法genericClass<T>.StaticMethod();例如,作爲...

是我最初的回答後,加入以上和我所希望的,這是已經解決以下腳註1 。但如果不清楚,這個簡單的語法將不起作用。你需要創造一些新的語法,因爲你可能有:

class Abc<T> { 
    void DoSomething(){ 
     GenericClass<T>.StaticMethod(); 
    } 
} 

namespace X { 
    class T { 
    } 
    class Abc { 
     void DoSomething(){ 
      GenericClass<T>.StaticMethod(); 
     } 
    } 
} 

在上面的兩個例子T已經由外部範圍界定。所以你需要一些其他的方式來說「我不想爲這個通用的第一個類型參數提供一個類型」。


例如,可以說GenericClass<T>.Showcase。任何允許它的新語法都不是那麼簡單。因爲a)調用上下文中的作用域中可能存在泛型類型參數T,或者b)泛型類型參數的名稱可能與調用上下文中作用域中的某個其他類型名稱衝突。

+0

感謝您的補充,您可以添加一個「第二,如果您的方法訪問任何靜態字段會發生什麼?使用泛型類型,每個獨特類型用作類型參數會導致一組新的靜態字段存在。 」。這是迄今爲止我認爲最有意義的論點。 –

+0

@SvenB - 如果您有任何「GenericClass 」的實例,並且它訪問一個靜態字段,它將與'GenericClass '的所有其他實例共享該靜態字段。但是這個特定的變量與'GenericClass '可以訪問的不一樣。靜態方法也可以訪問這些相同的字段,但它需要知道通用的「類型」是知道要訪問哪個靜態字段。 –

+1

@SvenB - 我已經在腳註1中添加了一些關於爲什麼你不能使用簡單語法的例子(甚至忽略了其他原因) –

5

因爲類是泛型的,所以使用它需要一個類型參數,即使靜態方法本身是非泛型的。類型參數不是可選的。

這就是爲什麼在泛型類上產生靜態成員導致CA1000 - 因爲這樣做要求您提供類型參數,即使它最終與該靜態成員無關。如果要創建與泛型類相關的靜態方法,請將它們放入非泛型輔助類中。

1

可以定義一個非通用類與相同

public class GenericClass { 
      public static void Showcase() 
     { 
      // your method 
     } 
} 
上通用的,可能衍生類的頂部

public class GenericClass<T> : GenericClass 

所以,你可以簡單地調用

GenericClass.Showcase(); 

它們實際上是兩個不同的類,但是無名命名慣例使它們強烈關聯。您的原始Showcase確實完全符合<T>.Showcase的要求,這就解釋了您爲什麼被迫指定類型的原因。

編輯

例如作爲添加型的靜態方法dosnt添加anythig(或不是嗎?)

可以通過指定通用T類型和int您目前使用

例如,如果你定義

public class GenericClass<T> 
{ 

    public static void Showcase(Func<int,T> conv, Func<T,int> inv) 

那麼你們之間的轉換概括的方法會寫

 GenericClass<T> list = new GenericClass<T>(); 

     for(int x = 0; x <10; x++) 
     { 
      list.AddHead(conv(x)); 
     } 

     System.Console.WriteLine("\nPrinting generic class using ints."); 
     foreach (T i in list) 
     { 
      System.Console.Write(inv(i) + ", "); 
     } 

和使用將是(當Tstring

GenericClass<string>.Showcase(x => x.ToString(),int.Parse); 
1

的方法被允許使用其包含類的T。例如:

class GenericClass<T> where T : new() 
{ 
    public static T GetOne() 
    { 
    return new T(); 
    } 
} 

有了,你可以說GenericClass<StringBuilder>.GetOne();得到一個新的StringBuilder,或GenericClass<int>.GetOne();得到一個零整數。

對於基本類庫中的示例,有Comparer<StringBuilder>.Create(...),它不是Comparer<int>.Create(...)

另一個問題是如果該方法使用static字段。每個替換Tstatic字段將有一個「副本」與實際類型。該方法需要知道它具有哪個T

類似地,如果該方法調用另一個使用T或其他靜態東西的static方法。


僅僅因爲你的特殊的方法恰好不使用T或任何類別的其他成員static,你還是要規定什麼T是。這與您必須指定方法參數的原因相同,即使方法不使用該參數。

0

爲什麼在調用泛型類的靜態方法時需要使用<T>

因爲泛型類是一個「藍圖」。靜態成員是按照構造類型共享的。

考慮這個泛型類:

public class Generic<T> 
{ 
    public static string Bar { get; set; } 
} 

然後使用它是這樣的:

Generic<string>.Bar = "Baz"; 
Generic<bool>.Bar = "Qux"; 

Console.WriteLine(Generic<string>.Bar); 
Console.WriteLine(Generic<bool>.Bar); 

將打印 「巴茲」,其次是 「Qux」。

+0

我明白,但我可以添加泛型 .Bar =「Foo」;這對我來說沒有什麼意義,但仍然有效。我明白'藍圖'需要一個類型,但是語法是隨機/混淆的,因爲添加一個類型不會改變任何結果。 –

+1

@SvenB如果您在'Showcase()'方法內添加了'System.Console.WriteLine(default(T));',如果'T'未知,應該發生什麼。或者如果你添加了'System.Console.WriteLine(typeof(T).Name);'? –

+1

@Sven _「添加一個類型不會改變任何結果」 - - 是的。靜態成員爲每個'T'生存一次。所以如果你的靜態方法使用靜態字段或屬性,它可能會顯示非常意外的行爲。如果你想省略它,編譯器應該爲'T','object'填充什麼?如果這與現有的代碼衝突,如果_does_使用'Generic .Bar'做什麼? – CodeCaster

相關問題