【问题标题】:Getting behavior of Java's Class<? extends Map> in .NET获取 Java 类的行为<?在 .NET 中扩展 Map>
【发布时间】:2016-06-14 07:53:16
【问题描述】:

我在java中有一个泛型类定义为:

public static class KeyCountMap<T> 
{
   private Map<T, MutableInt> map = new LinkedHashMap<T, MutableInt>();
   // ... rest of the properties...  

   public KeyCountMap()  
   { }  

   @SuppressWarnings({ "unchecked", "rawtypes" })  
   public KeyCountMap(Class<? extends Map> mapType) throws InstantiationException, IllegalAccessException   
   {
      map = mapType.newInstance();
   }  
   //... rest of the methods...  
}  

我在 .NET 中定义了相同的类:

public static class KeyCountMap<T>  
{  
   private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
   // ... rest of properties...  

   public KeyCountMap()  
   { }  

   public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>  
   {  
      obj = new T();  // Unable to define new instance of T
      map = obj;      // Unable to convert T to base class
   }  
}  

然后定义了一个方法,将KeyCountMap&lt;T&gt;类型的map按值降序排序。方法定义为:

public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> _map)
{
   List<KeyValuePair<T, MutableInt>> _list = new List<KeyValuePair<T, MutableInt>>(_map.EntrySet());  
   // whereas _map.EntrySet() return of type HashSet<KeyValuePair<T, MutableInt>>  
   _list = _list.OrderByDescending(_x => _x.Value).ToList();

   KeyCountMap<T> _result = new KeyCountMap<T>();
   foreach (KeyValuePair<T, MutableInt> _entry in _list)
   {
       _result.Put(_entry.Key, _entry.Value);
   }
   return _result; 
}

如何更正 .NET 中定义的类?

【问题讨论】:

  • 这样做的目的是什么?请注意,哈希表/地图/字典不保证任何顺序。您是否将 Java 音译为 C#?如果有,为什么?
  • 是的,为了我的项目需求,我正在音译
  • @acelent 我已经评论了你的回答(已接受),请看一下
  • @acelent 我是来应你的聊天邀请的。你在吗?
  • @acelent 你不在你邀请的聊天室里?你什么时候到?

标签: java c# generics inheritance instantiation


【解决方案1】:

我假设您知道 Java 在编译后会删除所有泛型类型信息(变量有元数据,但实际对象没有泛型类型信息)。此外,您的代码不是类型安全的:

@SuppressWarnings({ "unchecked", "rawtypes" })

您正在使用它,因为您正在创建 Map 的非参数化实例。

在 .NET 中,您无法像这样绕过类型系统,因为泛型类型信息在运行时保留并使用

让我们看看你的 C# 代码:

public static class KeyCountMap<T>  

C# 中的静态类是不能实例化的类,它仅用于其静态成员。我想你不想要这个。也许KeyCountMap 是 Java 中的静态嵌套类,而不是内部类。

在 C# 中,您没有内部类。嵌套类不与包含类的实例共享数据,就好像包含类的名称是嵌套类的命名空间的一部分。因此,您不需要,实际上也不想在这里使用 static 关键字。

{  
   private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();

在 .NET 中,Dictionary 是一个类。为了保持意图,您应该使用相应的接口IDictionary 作为map 字段的类型。

   // ... rest of properties...  

   public KeyCountMap()  
   { }  

   public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>  

为什么void返回类型,这不是构造函数吗?

在 C# 中,构造函数不能是泛型的。你可能想要Type

您的 C# 代码没有意义,所以您可以这样做:

   public KeyCountMap(Type dictionaryType)
   {
      if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
      {
          throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", nameof(dictionaryType));
      }
      map = (IDictionary<T, MutableInt>)Activator.CreateInstance(dictionaryType);
   }
}  

我们在创建实例之前检查类型。如果我们不这样做,我们将创建一个实例,强制转换将失败并且分配甚至不会发生,因此新实例将只是垃圾。

实际实例可能是代理;如果是这样,您可能不想在创建实例之前检查类型。


对于 works 的某些定义,您不能只是将 Java 复制粘贴为 C#(或反之亦然)并期望只进行一些更改直到它起作用,例如它编译。语言不是那么相似,很可能有太多微妙的事情是错误的。

这种方法一开始可能很有趣,但你会经常绊倒,很快就会完全失去乐趣。在开始逐行翻译代码之前,您应该学习基础知识并了解使用目标语言完成工作的方式。很多时候,您可能会发现在一个环境中必须做的事情已经存在于另一个环境中,反之亦然,或者在另一个环境中可能需要或多或少的步骤才能完成,等等。

在这种特殊情况下,Java 使 Class 成为泛型类,而 .NET 使 Type 保持非泛型类。在 .NET 中,只有接口和委托可以声明泛型类型协变或逆变。无论如何,这是相当严格的,如果Type 是通用的,那么预期的用途可以是协变的或逆变的。但请记住,在 Java 中,运行时的泛型 Class&lt;T&gt;Class 一样好,它只在编译时有任何价值,你可以告诉编译器你知道得更好,就像你做的那样。

【讨论】:

  • @acelent--谢谢你这么长的描述,你猜对了KeyCountMap是Java中的一个嵌套类,所以它在我的C#代码中也是一个嵌套类。
  • 你的构造函数nameof()的定义在当前上下文中不存在
  • "你的构造函数 nameof() 的定义在当前上下文中不存在" -- 那是 C# 6.0,在旧版本中用 "dictionaryType" 替换它。跨度>
  • 是的,我用dictionaryType.ToString();代替了它
  • "是的,我用dictionaryType.ToString();代替" -- 应该是参数的名称,所以请不要那样做.
【解决方案2】:

有两个问题。首先,你需要告诉编译器T有一个无参构造函数,所以你可以调用new T()。您可以通过为类定义提供 new() 参数来做到这一点。

您还必须告诉编译器 T 实际上是您要分配的字典,因此我们必须进一步扩展该类:

public class KeyCountMap<K>
{
    private Dictionary<K, MutableInt> map = new Dictionary<K, MutableInt>();
    // ... rest of properties...

请注意,K 是您尚未指定的字典的键类型。

其次,你的方法中的T可以是另一个T而不是你的类。省略即可:

public void Map()
{
    var obj = new Dictionary<K, MutableInt>();  // Unable to define new instance of T
    map = obj;      // Unable to convert T to base class
}

【讨论】:

  • 通过这样做,我能否获得与上面定义的 Java 类相同的功能?
  • 我不太确定 Java 类确实如此,但这至少可以修复您的错误。
  • 你从方法参数中删除了T obj,那么如何在方法定义中使用obj = new T();呢?
  • 您不必这样做,因为T 已经是您需要的类型,对吧?
  • 我必须有一个T 的新实例,然后将其分配给属性map
【解决方案3】:

也许这就是你想要的?

public class KeyCountMap<T>
    where T : new()
{
    private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
    // ... rest of properties...  

    public KeyCountMap()
    { }

    public KeyCountMap(T obj)
    {
        obj = new T();
        map = (Dictionary<T, MutableInt>)(object)obj;
    }
}

【讨论】:

  • 这和这个类的Java版本一样吗?
  • 那么像在 Java 中那样将类声明为静态的呢?
  • @Taufel:你想通过将其声明为静态来实现什么?我不认为它做你认为它做的......
  • 我引用了在 Java 类中声明的 static
  • @Taufel:是的,这没有回答我的问题。
猜你喜欢
  • 1970-01-01
  • 2011-02-08
  • 2012-01-06
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 2011-03-22
  • 1970-01-01
相关资源
最近更新 更多