2016-06-14 5 views
0

У меня есть общий класс в Java определяется как:Получение поведения класса Java <? расширяет карты> в .NET

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<T> по значению в порядке убывания. Метод определяется как:

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?

+0

Какова цель этого? Обратите внимание, что хеш-таблицы/карты/словари не гарантируют никакого заказа. Вы * транслитерируете * Java на C#? Если да, то почему? – acelent

+0

Да, я транслитерирую ради моих требований к проекту – maliks

+0

@acelent Я прокомментировал ваш ответ (принят), пожалуйста, посмотрите – maliks

ответ

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); 
    } 
} 

Мы проверяем тип перед созданием экземпляра. Если бы мы этого не сделали, мы бы создали экземпляр, приведение не получилось бы, и назначение не произойдет, так что новый экземпляр будет просто мусором.

Возможно, фактический экземпляр будет прокси; Если это так, вы можете не захотеть проверить тип перед созданием экземпляра.


Вы не можете просто скопировать и вставить Java в C# (или наоборот) и ожидать, чтобы сделать всего несколько изменений, пока он работает, для некоторого определения работы, например он компилируется. Языки не так похожи, и, скорее всего, слишком много тонких вещей ошибочны.

Этот подход может быть интересным сначала, но вы будете спотыкаться так часто, что он скоро перестанет быть вообще забавным. Вы должны изучить основы и понять, как все делается на целевом языке, прежде чем начинать перевод кода по строкам. Много раз вы можете обнаружить, что что-то, что вам нужно было сделать в одной среде, уже существует в другой или наоборот, или что-то может предпринять более или менее шаги для других целей и т. Д.

В данном конкретном случае , Java, сделанный Class, будет общим классом, тогда как .NET сохранил Type не-общий класс. В .NET только интерфейсы и делегаты могут указывать общую ковариацию или контравариантность. В любом случае это является довольно ограничительным, если Type является общим, предполагаемое использование может быть либо ковариантным, либо контравариантным. Но помните, что в Java общий Class<T> во время выполнения так же хорош, как и Class, он имеет только какое-либо значение во время компиляции, и вы можете сказать, что компилятор, которого вы знаете лучше, так или иначе.

+0

@ acelent - спасибо за столь длинное описание, вы догадались, что 'KeyCountMap' является вложенным классом в Java, поэтому его также вложенный класс в моем C# -коде. – maliks

+0

Определение вашего конструктора 'nameof()' не существует в текущем контексте – maliks

+0

* «Определение вашего конструктора' nameof() 'не существует в текущем контексте» * - Это C# 6.0, замените его на ' "dictionaryType" 'в более старых версиях. – acelent

1

Есть две проблемы. Во-первых, вам нужно сообщить компилятору, что 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 
} 
+0

Сделав это, смогу ли я получить такую ​​же функциональность, как в Java-классе, определенном выше? – maliks

+0

Я не совсем уверен, что класс Java делает, но это, по крайней мере, исправит ваши ошибки. –

+0

Вы удалили 'T obj' из параметров метода, так как использовать вместо этого' obj = new T(); 'в определении метода? – maliks

0

Возможно, это то, что вы хотите?

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; 
    } 
} 
+0

Это то же самое, что и в Java-версии этого класса? – maliks

+0

и как объявить класс статическим, как в Java? – maliks

+0

@Taufel: Что вы пытаетесь достичь, объявив его статичным? Я не думаю, что он делает то, что, по вашему мнению, делает ... – Mehrdad