在泛型类中为静态方法设置无类型

时间:2016-01-16 23:14:02

标签: c# generics

不是Java的粉丝,但Java不允许为泛型类设置类型,在这种情况下,它会将类型威胁为Object类型。但是,据我所知,C#强制在任何时候必须实例化泛型类或简单地使用时设置<T>的类型。但是,让我们说我们有一个泛型类,我们需要一个静态方法,它不依赖于<T>的类型。

首先,我们知道它可以移动到一个单独的上下文,或者我们可以设置一个虚拟类型<T>,但作为一个编程难题有任何方法可以调用它没有定义类型T

示例:

 class Test<T> where T: ITestable {
     ...
     public static void CreateTestFile(String fileName) {...}
 }
 Test.CreateTestFile("test.txt");

这可以用Java完成,显然不能用于C#。但我只是想确定一下。

2 个答案:

答案 0 :(得分:8)

Java和C#以不同的方式实现泛型:

  • Java使用类型擦除,这基本上意味着在编译时,您放入<T>的任何内容都将被删除并变为ObjectSomething<Foo>Something<Bar>在运行时将是相同的类型,并且实际上将等于Something<Object>

  • C#使用运行时具体化,这意味着对于使用不同T的每种类型,运行时通过使用开放的通用版本完全生成一个新类作为模板(这意味着它也会在您调用它时每T生成一次底层本机代码)。就CLR而言,Something<Foo>Something<Bar>是两种不相关的类型。

希望你理解为什么这种差异对你的场景很重要。忽略T在Java中是微不足道的,但在C#中却不那么容易。

如果您的代码中不需要T,请使用非通用方法:

abstract class Test
{
    public static void CreateTestFile(String fileName) {...}
}

class Test<T> : Test
    where T : ITestable
{
     ...
}

在这里,这样做更好:)

另外,请注意,对于实例方法,您可以使用协变逆变接口在编译时放宽对已知T的要求。例如,如果您使用协变接口,则只需要知道T的基本类型。

答案 1 :(得分:2)

您应该考虑将您的问题分开,将公共静态方法放在别处。但是,如果您真的想要调用它,这可以正常工作:

class Program
{
    static void Main(string[] args)
    {
        Test<ITestable>.CreateTestFile("test.txt");
    }
}

class Test<T> where T : ITestable
{
     public static void CreateTestFile(String fileName) { }
}

public interface ITestable { }

如果你有约束where T : class, new(),你可以做类似的事情:

class Program
{
    static void Main(string[] args)
    {
        Test<object>.CreateTestFile("test.txt");
    }
}

class Test<T> where T : class, new()
{
     public static void CreateTestFile(String fileName) { }
}

public interface ITestable { }

如果你有一个更奇怪的约束,如where T : class, ITestable, new()我不再担心让编译器跳过你的设计,重新考虑你的设计,并将这些问题分开:

class Program
{
    static void Main(string[] args)
    {
        Util.CreateTestFile("test.txt");
    }
}

class Util
{
    public static void CreateTestFile(String fileName) { }
}

class Test<T> where T : class, ITestable, new()
{
    /*...*/
}

public interface ITestable { }