简体   繁体   English

没有为泛型类中的静态方法设置类型

[英]Set no type for a static method in a generic class

Not a fan of Java, but Java allows not setting types for generic classes and in that case it threats the type as Object type. 不是Java的狂热者,但是Java不允许设置通用类的类型,在这种情况下,它会将类型威胁为“ Object类型”。 However, as far as I know, C# enforces setting the type of <T> anytime the generic class has to be instantiated or simply speaking used. 但是,据我所知,C#在必须实例化或仅使用泛型类的任何时候强制设置<T>的类型。 However, let's say that we have a generic class, and we need a static method in there which does not rely on the type of <T> . 但是,假设我们有一个通用类,并且在其中需要一个不依赖<T>类型的静态方法。

Firstly, we know that it can be moved to a separate context or we can set a dummy type of <T> , but as a programming puzzle is there any way to call it Without defining the type of T ? 首先,我们知道可以将其移动到单独的上下文中,也可以将其设置为<T>的伪类型,但是作为编程难题,有什么方法可以调用它而不定义T的类型

Example: 例:

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

This can be done Java and apparently can't be in C#. 可以使用Java完成此操作,显然不能使用C#。 But I just wanna make sure. 但我只想确定。

Java and C# implement generics differently: Java和C#实现泛型的方式有所不同:

  • Java uses type erasure , which basically means that at compile time, anything you put in <T> is erased and becomes Object . Java使用类型擦除 ,从根本上讲 ,这意味着在编译时,您放入<T>被擦除并成为Object Something<Foo> and Something<Bar> will be the same type at runtime, and wil be effectively equal to Something<Object> . Something<Foo>Something<Bar>在运行时将是相同的类型,并且实际上等于Something<Object>

  • C# uses run-time reification , meaning that for each type you use with a distinct T , the runtime generates a new class altogether, by using the open generic version as a template (which means it also generates the underlying native code once per T as you call it). C#使用运行时规范化 ,这意味着对于使用不同的T每种类型,运行时通过使用开放的通用版本作为模板来总计生成一个新类(这意味着它还会为每个T生成一次底层本机代码)。您称之为)。 Something<Foo> and Something<Bar> are two unrelated types as far as the CLR is concerned. 就CLR而言, Something<Foo>Something<Bar>是两个不相关的类型。

Hopefully you understand why this difference is important to your scenario. 希望您理解为什么这种差异对您的情况很重要。 Ignoring T is trivial in Java, but not so easy in C#. 在Java中忽略T很简单,但在C#中却不那么容易。

If you don't need T in your code, then use a non-generic method: 如果您的代码中不需要T ,请使用非泛型方法:

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

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

Here, that's better :) 在这里,那更好:)

Also, note that for instance methods, you can use covariant and contravariant interfaces to loosen the requirement for a known T at compile-time. 另外,请注意,对于实例方法,您可以使用协变逆变接口在编译时放宽对已知T的要求。 For instance, if you use a covariant interface, you only need to know a base type of T . 例如,如果您使用协变接口,则只需知道T的基本类型。

You should really consider separating your concerns, placing that public static method elsewhere. 您应该真正考虑分离您的关注点,将该公共静态方法放在其他地方。 However, if you really want to call it, this would work just fine: 但是,如果您真的要调用它,那么就可以了:

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

If you had a constraint where T : class, new() , you could do something similar: 如果您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 { }

If you had an even weirder constraint like where T : class, ITestable, new() I'd stop worrying about getting the compiler to jump through your hoops, rethink your design, and separate the concerns along these lines: 如果您有一个甚至更奇怪的约束,例如where T : class, ITestable, new()我将不再担心让编译器跳入where T : class, ITestable, new() ,重新考虑您的设计,并按照以下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 { }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM