为什么我必须在泛型类的静态方法调用上使用<t>

时间:2017-02-20 10:41:48

标签: c# generics

我跟随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 + ", ");
            }
        }
    }
}

除了静态Showcase方法之外,它与链接的示例几乎完全相同。

现在在我的主要方法中我可以打电话:

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 个答案:

答案 0 :(得分:5)

因为类是通用的,所以使用它需要一个类型参数,即使静态方法本身是非泛型的。类型参数不是可选的。

这就是为什么在泛型类上使用静态成员会导致CA1000 - 因为这样做需要您提供类型参数,即使它最终与该静态成员无关。如果要创建与泛型类相关的静态方法,请将它们放在非泛型辅助类中。

答案 1 :(得分:5)

由于您尚未创建名为GenericClass的课程,因此您创建了一个名为GenericClass<T>的开放式通用课程。

没有什么可以阻止你在同一名称空间中创建一个类GenericClass,也没有什么可以阻止你创建一个名为GenericClass<T1,T2>的类。所有这些都可以存在于同一名称空间中,并且它们之间没有明确或隐含的关系,除非您声明一个。

所以,如果你想在&#34;在一个类型参数&#34;中通用的GenericClass类调用静态方法,你必须以某种方式说出来,并且你已经找到了怎么做 - 通过提供一个类型参数。

有人可能会说,如果静态方法没有使用类型参数,那么它是多余的 - 那么为什么不能仅仅通过使用静态打开类型参数来调用它?那么,首先是因为那必须是新的语法才能允许发生 1 。第二,如果您的方法访问任何静态字段会发生什么?对于泛型类型,用作类型参数的每个唯一类型都会导致存在一组新的静态字段。

  

为什么静态方法genericClass<T>.StaticMethod();的语法不是例如......

在我的初步回答之后添加了以上内容,我希望这已在下面的脚注1中解决。但是,如果不清楚,这个简单的语法将无法正常工作。你需要发明一些新的语法,因为你可能有:

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

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

在上述两个示例中,T已由外部范围定义。所以你需要一些其他的说法&#34;我不想为这个通用的第一个类型参数提供类型&#34;。

1 E.g。可以说GenericClass<T>.Showcase。任何允许它的新语法都不会那么简单。因为a)调用上下文中的范围可能存在泛型类型参数T,或者b)泛型类型参数的名称可能与调用上下文中的范围内的某些其他类型名称冲突。

答案 2 :(得分:1)

您可以使用相同的名称

定义非泛型类
public class GenericClass {
            public static void Showcase()
        {
            // your method
        }
}

在通用的,可能派生的类

之上
public class GenericClass<T> : GenericClass

这样你就可以直接打电话了

    GenericClass.Showcase();

他们实际上是两个不同的类,但他们的命名约定使它们密切相关。您的原始Showcase确实完全符合<T>.Showcase的条件,这就解释了您被迫指定类型的原因。

修改

  

例如,在静态方法dosnt中添加一个类型add 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);

答案 3 :(得分:1)

允许该方法使用其包含类的T。例如:

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

您可以说GenericClass<StringBuilder>.GetOne();获取新的StringBuilderGenericClass<int>.GetOne();以获得零整数。

对于基类库中的示例,Comparer<StringBuilder>.Create(...)不是Comparer<int>.Create(...)

另一个问题是该方法是否使用static字段。对于具有实际类型的static,每个替换T字段将有一个“副本”。该方法需要知道它具有哪个T

同样,如果该方法调用另一个使用static或其他静态内容的T方法。

仅仅因为您的特定方法不使用T或该类的任何其他static成员,您仍需指定T是什么。这与您必须指定方法参数的原因相同,即使该方法不使用该参数也是如此。

答案 4 :(得分: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);

将打印“Baz”,然后打印“Qux”。