Getting behavior of Java's Class<? extends Map> in .NET

前端 未结 3 2010
一个人的身影
一个人的身影 2021-01-16 21:04

I have a generic class in java defined as:

public static class KeyCountMap 
{
   private Map map = new LinkedHashMap

        
3条回答
  •  南笙
    南笙 (楼主)
    2021-01-16 21:49

    I assume you know Java erases any generic type information after compiling (there's metadata for variables, but actual objects are void of generic type information). Moreover, your code is not type safe:

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

    You're using this because you're creating a non-parameterized instance of Map.

    In .NET, you don't get around the type system like this, because generic type information is kept and used at runtime.

    Let's see your C# code:

    public static class KeyCountMap  
    

    A static class in C# is a class that cannot be instanced, it's used for its static members alone. I think you don't want this. Perhaps KeyCountMap is a static nested class in Java, as opposed to an inner class.

    In C#, you don't have inner classes. Nested classes don't share data with an instance of the containing class, it's as if the name of the containing class is part of the namespace for the nested class. So, you don't need, and actually don't want, the static keyword here.

    {  
       private Dictionary map = new Dictionary();
    

    In .NET, Dictionary is a class. To keep the intent, you should use IDictionary, the corresponding interface, as the type for the map field.

       // ... rest of properties...  
    
       public KeyCountMap()  
       { }  
    
       public void KeyCountMap(T obj) where T : Dictionary  
    

    Why the void return type, isn't this a constructor?

    In C#, constructors can't be generic. You probably want a Type.

    Your C# code just doesn't make sense, so here's what you could do:

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

    We're checking the type before creating an instance. If we didn't, we would create an instance, the cast would fail and the assignment wouldn't even happen, so the new instance would just be garbage.

    It may be that the actual instance will be a proxy; if so, you may not want to check the type before creating an instance.


    You can't just copy-paste Java as C# (or vice-versa) and expect to make just a few changes until it works, for some definition of works, e.g. it compiles. The languages are not that similar, and chances are that too many subtle things are wrong.

    This approach might be fun at first, but you'll stumble so often it will soon stop being any fun at all. You should learn the basics and understand the way things are done in the target language before you start translating code line-by-line. Many times, you may find that something you had to do in one environment already exists in the other or vice-versa, or that something may take more or less steps to do in the other, etc.

    In this particular case, Java made Class be a generic class, while .NET kept Type a non-generic class. In .NET only interfaces and delegates may state generic type covariance or contravariance. This is rather restrictive anyway, if Type was generic, the intended uses could be either covariant or contravariant. But remember that in Java, a generic Class at runtime is as good as Class, it only has any value at compile time and you can tell the compiler you know better anyway, just like you did.

提交回复
热议问题