获取Java类的行为
我在java中有一个generics类定义为:
public static class KeyCountMap { private Map map = new LinkedHashMap(); // ... rest of the properties... public KeyCountMap() { } @SuppressWarnings({ "unchecked", "rawtypes" }) public KeyCountMap(Class mapType) throws InstantiationException, IllegalAccessException { map = mapType.newInstance(); } //... rest of the methods... }
我在.NET中定义了相同的类:
public static class KeyCountMap { private Dictionary map = new Dictionary(); // ... rest of properties... public KeyCountMap() { } public void KeyCountMap(T obj) where T : Dictionary { obj = new T(); // Unable to define new instance of T map = obj; // Unable to convert T to base class } }
然后定义一个方法来按降序对值KeyCountMap
类型的映射进行排序。 该方法定义为:
public static KeyCountMap SortMapByDescendValue(KeyCountMap _map) { List<KeyValuePair> _list = new List<KeyValuePair>(_map.EntrySet()); // whereas _map.EntrySet() return of type HashSet<KeyValuePair> _list = _list.OrderByDescending(_x => _x.Value).ToList(); KeyCountMap _result = new KeyCountMap(); foreach (KeyValuePair _entry in _list) { _result.Put(_entry.Key, _entry.Value); } return _result; }
如何更正.NET中定义的类?
我假设您知道Java在编译后会删除任何generics类型信息(变量的元数据,但实际对象没有generics类型信息)。 而且,您的代码不是类型安全的:
@SuppressWarnings({ "unchecked", "rawtypes" })
你正在使用它,因为你正在创建一个非参数化的Map
实例。
在.NET中,您不会像这样绕过类型系统,因为在运行时保留并使用generics类型信息。
让我们看看你的C#代码:
public static class KeyCountMap
C#中的静态类是一个无法实例化的类,它仅用于静态成员。 我想你不想要这个。 也许KeyCountMap
是Java中的静态嵌套类,而不是内部类。
在C#中,您没有内部类。 嵌套类不与包含类的实例共享数据,就好像包含类的名称是嵌套类的命名空间的一部分。 因此,您不需要,实际上也不需要这里的static
关键字。
{ private Dictionary map = new Dictionary();
在.NET中, Dictionary
是一个类。 为了保持意图,您应该使用IDictionary
(相应的接口)作为map
字段的类型。
// ... rest of properties... public KeyCountMap() { } public void KeyCountMap(T obj) where T : Dictionary
为什么void
返回类型,这不是一个构造函数?
在C#中,构造函数不能是通用的。 你可能想要一个Type
。
你的C#代码没有意义,所以这是你可以做的:
public KeyCountMap(Type dictionaryType) { if (!typeof(IDictionary).IsAssignableFrom(dictionaryType)) { throw new ArgumentException("Type must be a IDictionary", nameof(dictionaryType)); } map = (IDictionary)Activator.CreateInstance(dictionaryType); } }
我们在创建实例之前检查类型。 如果我们没有,我们将创建一个实例,转换将失败,甚至不会发生赋值,因此新实例将只是垃圾。
可能是实际的实例将是代理; 如果是这样,您可能不想在创建实例之前检查类型。
你不能只是将Java复制粘贴为C#(反之亦然),并期望在它工作之前做一些改变,对于一些工作的定义,例如它编译。 语言并不是那么相似,很可能有太多微妙的事情是错误的。
这种方法起初可能很有趣,但是你经常会绊倒它很快就会停止变得有趣。 在逐行开始翻译代码之前,您应该学习基础知识并了解目标语言的完成方式。 很多时候,您可能会发现在一个环境中必须要做的事情已经存在于另一个环境中,反之亦然,或者在另一个环境中可能需要采取更多或更少的步骤,等等。
在这种特殊情况下,Java使Class
成为generics类,而.NET保持Type
为非generics类。 在.NET中,只有接口和委托可以声明generics类型协方差或逆变。 无论如何,这是相当严格的,如果Type
是通用的,预期用途可以是协变的或逆变的。 但请记住,在Java中,运行时的genericsClass
与Class
一样好,它在编译时只有任何值,你可以告诉编译器你知道的更好,就像你一样。
有两个问题。 首先,您需要告诉编译器T
有一个无参数构造函数,因此您可以调用new T()
。 您可以通过向类定义提供new()
参数来实现。
您还必须告诉编译器T
实际上是您要分配的字典,因此我们必须更多地扩展该类:
public class KeyCountMap { private Dictionary map = new Dictionary(); // ... rest of properties...
请注意, K
是字典的键类型,您尚未指定。
其次,你方法中的T
可以是你class级中的另一个T
省略这将解决问题:
public void Map() { var obj = new Dictionary(); // Unable to define new instance of T map = obj; // Unable to convert T to base class }
也许这就是你想要的?
public class KeyCountMap where T : new() { private Dictionary map = new Dictionary(); // ... rest of properties... public KeyCountMap() { } public KeyCountMap(T obj) { obj = new T(); map = (Dictionary)(object)obj; } }