Использование инструкции с обобщениями: использование ISet = System .Коллекции.Общий.ISet

#c#

#c# #обобщения #синтаксис #псевдоним #использование

Вопрос:

Поскольку я использую два разных общих пространства имен коллекций ( System.Collections.Generic и Iesi.Collections.Generic ), у меня возникают конфликты. В других частях проекта я использую как фреймворки nunit, так и mstest, но уточняю, что при вызове Assert я хочу использовать версию nunit с помощью

 using Assert = NUnit.Framework.Assert;
 

Который отлично работает, но я хочу сделать то же самое с универсальными типами. Однако следующие строки не работают

 using ISet = System.Collections.Generic.ISet;
using ISet<> = System.Collections.Generic.ISet<>;
 

Кто-нибудь знает, как сообщить .net, как использовать инструкцию using с обобщениями?

Комментарии:

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

2. Эрик, я впервые сталкиваюсь с этой проблемой, поскольку платформа .net 4.0 добавила ISet<> и Iesi. Библиотеки dll Collections нацелены на 3.5. Обычно другие разработчики хорошо относятся к тому, чтобы не конфликтовать со стандартным именованием .net.

3. Почему у вас это в двух разных пространствах имен? Можете ли вы предоставить дополнительную информацию?

4. Я бы сформулировал это по-другому. Намеренное использование одного и того же имени для двух разных вещей будет неудобным. Это работает лучше всего, если у вас крайне маловероятно using одновременное использование двух пространств имен.

5. @EricLippert При преобразовании кода из Java или Haskell или других языков, поддерживающих точный импорт символов (т. Е. import myModule.MyClass; В Java, я обнаружил, что это серьезный недостаток C #, потому что вам нужно using все, System.Collections.Generic даже если вам нужно только IEnumerable<> для вашего выражения LINQ. Java не разрешает переименование, но я думаю, что переименование импорта на самом деле запрашивается «иногда», а не точный импорт / использование.

Ответ №1:

К сожалению, using директива не делает то, что вы хотите. Вы можете сказать:

 using Frob = System.String;
 

и

 using ListOfInts = System.Collections.Generic.List<System.Int32>;
 

но вы не можете сказать

 using Blob<T> = System.Collections.Generic.List<T>
 

или

 using Blob = System.Collections.Generic.List
 

Это недостаток языка, который никогда не исправлялся.

Комментарии:

1. Каков наилучший способ лоббировать эту функцию?

2. @miniBill: попробуйте опубликовать на форуме по языковому дизайну по адресу Roslyn.codeplex.com .

3. Здесь есть предложение. Я тоже хотел бы иметь эту функцию.

Ответ №2:

Я думаю, вам лучше использовать псевдонимы самих пространств имен, а не универсальных типов (что, я думаю, невозможно).

Так, например:

 using S = System.Collections.Generic;
using I = Iesi.Collections.Generic;
 

Затем для BCL ISet<int> , например:

 S.ISet<int> integers = new S.HashSet<int>();
 

Комментарии:

1. Очень хорошее предложение! Только что столкнулся с точно такой же проблемой, и это не сразу пришло мне в голову.

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

3. Просто столкнулся с той же проблемой. Я хочу использовать константы, определенные в универсальном классе, в качестве значений параметров по умолчанию для конструктора, и их всего 4, поэтому мне нужно ввести полное, длинное имя класса с его общими параметрами плюс имя константы. Это можно было бы решить, если бы язык разрешал использовать операторы внутри универсального класса, например using C = Long.Name<TKey,TValue> . За пределами класса общие параметры неизвестны, поэтому это бесполезно.

Ответ №3:

Единственный способ, которым вы можете создать псевдоним универсального типа, — это специализировать его следующим образом.

 using IntSet = System.Collections.Generic.ISet<int>;
 

Вы не можете использовать псевдоним открытого универсального типа, как вы сделали в своем примере:

 using MySet = System.Collections.Generic.ISet<>;
 

Комментарии:

1. Спасибо, Стив, я смогу использовать это позже!

2. Почему ваш первый пример не будет компилироваться на VS2017?

Ответ №4:

Ваше имя псевдонима совпадает с именем самого класса, поэтому у вас все еще есть двусмысленность, как если бы у вас было using для каждого пространства имен. Дайте псевдониму класса другое имя, т.е.:

 using FirstNamespace;
using OtherObject = SecondNamespace.MyObject;

public class Foo
{
    public void Bar()
    {
        MyObject first = new MyObject;//will be the MyObject from the first namespace
        OtherObject second = new OtherObject;
    }
}
 

Ответ №5:

В некоторых случаях вы можете использовать наследование:

 public class MyList<T1, T2> : List<Tuple<IEnumerable<HashSet<T1>>, IComparable<T2>>> { }

public void Meth()
{
    var x = new MyList<int, bool>();
}
 

Ответ №6:

Вы можете создать псевдоним класса, выполнив :

 using Test = NameSpace.MyClass;
 

Только если класс НЕ является универсальным.

Комментарии:

1. Вы можете создать псевдоним универсального класса, вам просто нужно указать конкретный тип в псевдониме, а не оставлять его универсальным.