.Net等效于Java类型类<>;?

.Net等效于Java类型类<>;?,java,.net,generics,casting,Java,.net,Generics,Casting,我是一个.NET的人,所以让我首先强调我对一些Java概念的理解——如果我错了,请纠正我 Java泛型支持有界通配符的概念: Java的类描述了一种类型,大致相当于.NET类 到目前为止,一切顺利。但是我找不到与Java一般类型的类足够接近的等价性,其中t是一个有界通配符。这基本上对类表示的类型施加了限制 让我举一个Java的例子 String custSortclassName = GetClassName(); //only known at runtime,

我是一个.NET的人,所以让我首先强调我对一些Java概念的理解——如果我错了,请纠正我

Java泛型支持有界通配符的概念:

Java的类描述了一种类型,大致相当于.NET类

到目前为止,一切顺利。但是我找不到与Java一般类型的
足够接近的等价性,其中t是一个有界通配符。这基本上对
表示的类型施加了限制

让我举一个Java的例子

String custSortclassName = GetClassName(); //only known at runtime, 
                                           // e.g. it can come from a config file
Class<? extends IExternalSort> customClass 
    = Class.forName("MyExternalSort")
        .asSubclass(IExternalSort.class);  //this checks for correctness

IExternalSort impl = customClass.newInstance(); //look ma', no casting!
Java版本在我看来更干净。
有什么方法可以改进.NET版本吗?

您可以使用“as”操作符获得稍微漂亮一点的版本:

String custSortclassName = GetClassName();
Assembly assy = GetAssembly();
Type customClass = assy.GetType(custSortclassName);

IExternalSort impl = Activator.CreateInstance(customClass) as IExternalSort;
if(impl==null) throw new InvalidOperationException(...);
但在这里,我在检查其类型之前创建实例,这可能是您的问题。

C#泛型是声明站点差异,类型参数的差异是固定的

Java是使用站点差异的,所以一旦我们有了一个声明
列表
,我们就可以用3种方法来使用它

List<Number>           // invariant, read/write
List<+Number>          // covariant, read only
List<-NUmber>          // contravariant, write only
List//不变量,读/写
列表//协变,只读
列表//逆变,仅写
这两种方法都有利弊。使用站点的方法显然更强大,尽管它因对程序员来说太难而赢得了声誉。我认为这其实很容易掌握

List<Integer> integers = ...;
List<+Number> numbers = integers;  // covariant
列出整数=。。。;
列表编号=整数;//协变的
不幸的是,Java发明了一种非常可怕的语法

List<? extends Number>    //  i.e. List<+Number>

List您可以尝试编写如下扩展方法:

 static class TypeExtension
    {
        public static I NewInstanceOf<I>(this Type t) 
            where  I: class 
        {
            I instance = Activator.CreateInstance(t) as I;
            if (instance == null)
                throw new InvalidOperationException();
            return instance;
        }
    }
静态类类型扩展
{
公共静态I NewInstanceOf(此类型为t)
我在哪里上课
{
I instance=Activator.CreateInstance(t)作为I;
if(实例==null)
抛出新的InvalidOperationException();
返回实例;
}
}
然后可按以下方式使用:

String custSortclassName = GetClassName(); //only known at runtime, 
                                           // e.g. it can come from a config file

Assembly assy = GetAssembly();
Type customClass = assy.GetType(custSortclassName);            

IExternalSort impl = customClass.NewInstanceOf<IExternalSort>();
String custSortclassName=GetClassName()//只有在运行时才知道,
//例如,它可以来自配置文件
Assembly assy=GetAssembly();
类型customClass=assy.GetType(custSortclassName);
IExternalSort impl=customClass.NewInstanceOf();

使用扩展方法&一个自定义的包装类,您可以非常接近Java语法

注意:不能用于测试类型是否实现了接口-请参阅MSDN上的链接文档。你可以改为使用-参见下面的代码

使用系统;
类类型
{
只读类型;
公共类型(类型类型)
{
//检查子类型关系
如果(!typeof(T).IsAssignableFrom(type))
抛出新ArgumentException(“传递的类型必须是“+typeof(T).Name,“type”的子类型);
this.type=type;
}
公共类型underyingtype
{
获取{返回this.type;}
}
}
静态类类型扩展
{
公共静态类型AsSubclass(此System.Type)
{
返回新类型(类型);
}
}
//如果需要,可以扩展此类
静态类TypeWrapperExtensions
{
公共静态T CreateInstance(此类型)
{
return(T)Activator.CreateInstance(type.underyingType);
}
}
使用界面差异进行进一步改进
(应该只在性能评估后在生产代码中使用。可以通过使用(并发!)缓存字典
concurrentDictionary来改进。这可能有点太简单了,但是否可以简单地添加
new()
对where限制的约束?类似于
MyExternalSort:IExternalSort where T:IExternalSort,new()
然后使用
var impl=new T()
?就我个人而言,我会使用工厂模式来创建在这种情况下实现相同接口的类型的实例。我不太了解Java泛型,但我知道它们的实现方式不同(不支持JVM),并且支持许多.NET泛型所不支持的东西。所以不要指望找到一个直接的“等价物”对于everything@Aschratt我不明白这与我的问题有什么关系。如果在编译时知道所有类型信息,那么这个技巧可能会很有用,但MyExternalSort类型直到运行时才知道-它很可能由我的排序库的客户端实现,并且只由名称指定。@jalf我知道类型擦除,所以我确信我并不期望1:1映射。我只是希望比我目前不太漂亮的实现有一些改进。@Cristi Diaconescu:编译时不需要知道专用类型。它只需要适合您的约束(从IExternalSort继承,无参数构造函数)在编译时,当你不知道它的确切类型时,你也可以提供一些参数作为IExternalSort实例。
as
操作符也执行强制转换。唯一的区别是,如果强制转换不成功,它不会引发异常。这并没有让它变得更容易。我想我现在明白你的答案了虽然它和我的更相关。也许你可以看看。
List<? extends Number>    //  i.e. List<+Number>
 static class TypeExtension
    {
        public static I NewInstanceOf<I>(this Type t) 
            where  I: class 
        {
            I instance = Activator.CreateInstance(t) as I;
            if (instance == null)
                throw new InvalidOperationException();
            return instance;
        }
    }
String custSortclassName = GetClassName(); //only known at runtime, 
                                           // e.g. it can come from a config file

Assembly assy = GetAssembly();
Type customClass = assy.GetType(custSortclassName);            

IExternalSort impl = customClass.NewInstanceOf<IExternalSort>();