Набор универсальных типов

Это выражение <!--.+?(?<=[\*\r\n])--> соответствовало многострочным комментариям только в Notepad ++.

31
задан John Saunders 9 July 2010 в 18:17
поделиться

8 ответов

Пусть ваш класс generic наследуется от не generic base, или реализует не generic interface. Тогда вы можете иметь коллекцию этого типа и выполнять приведение в любом коде, который вы используете для доступа к содержимому коллекции.

Вот пример.

public abstract class MyClass
{
    public abstract Type Type { get; }
}

public class MyClass<T> : MyClass
{
    public override Type Type
    {
        get { return typeof(T); }
    }

    public T Value { get; set; }
}

// VERY basic illustration of how you might construct a collection
// of MyClass<T> objects.
public class MyClassCollection
{
    private Dictionary<Type, MyClass> _dictionary;

    public MyClassCollection()
    {
        _dictionary = new Dictionary<Type, MyClass>();
    }

    public void Put<T>(MyClass<T> item)
    {
        _dictionary[typeof(T)] = item;
    }

    public MyClass<T> Get<T>()
    {
        return _dictionary[typeof(T)] as MyClass<T>;
    }
}
30
ответ дан 27 November 2019 в 22:18
поделиться

Единственный способ, которым я могу придумать, вне головы - это следующее (завернуто в консольное приложение для тестирования):

class Program
{
    static void Main(string[] args)
    {
        var x = new MyClass<string>() { Value = "34" };
        var y = new MyClass<int>() { Value = 3 };

        var list = new List<IMyClass>();
        list.Add(x);
        list.Add(y);

        foreach (var item in list)
        {
            Console.WriteLine(item.GetValue);
        }
    }

    private interface IMyClass
    {
        object GetValue { get; }
    }

    private class MyClass<T> : IMyClass
    {
        public T Value;

        public object GetValue
        {
            get
            {
               return Value;
            }
        }
    }
}

, т.е. Пусть MyClass реализует пустой интерфейс, а затем создает ваши коллекции в виде экземпляров классов, которые реализуют этот интерфейс.

Обновление: Я добавил метод «GetValue» в интерфейс, который позволяет вам получить доступ к «Значение» экземпляра MyClass как объекта. Насколько это возможно, если вы хотите иметь коллекцию, содержащую смешанные типы.

8
ответ дан Rob 27 November 2019 в 22:18
поделиться

Я думаю, что проблема в том, что универсальные классы на самом деле совсем не одного типа. Это просто шаблоны, которые создают совершенно новые типы во время компиляции (если я правильно понимаю). Следовательно, MyClass<int> и MyClass<string> являются полностью различными типами, в зависимости от времени выполнения. Это также могут быть MyIntClass и MyStringClass, которые вы, очевидно, не можете иметь в одном и том же списке, не поместив их в квадрат. Они не (обязательно) наследуют один и тот же базовый класс, реализуют те же интерфейсы или что-то еще. Они такие же разные, как и любые другие два типа, и вы должны относиться к ним как таковым (даже если вы думаете, что знаете лучше).

Конечно, вы можете сделать так, чтобы они реализовали интерфейс, унаследовали базовый объект или любые другие опции, которые уже были предоставлены. Взгляните на ответ commongenius , чтобы найти хороший способ сделать это.

2
ответ дан Community 27 November 2019 в 22:18
поделиться

Я считаю, что ваша коллекция должна быть одного типа MyClass (как и в T, должна быть одинаковой), потому что компилятор не будет знать, какие типы вы добавили к каким элементам в коллекции.

Другими словами, если вам нужно добавить 2 элемента в список:

list.Add(new MyClass<string>());
list.Add(new MyClass<int>());

, то попробуйте сослаться на один из них:

var myItem = list[1];

Компилятор не знает, что общего был назначен списку MyClass в элементе 1 , потому что элементы добавляются во время выполнения, но общие значения определяются во время компиляции.

Я уверен, что то, что вы хотите сделать, не может быть сделано.


Если вы заранее знаете количество элементов, возможно, вы могли бы использовать кортеж ?

1
ответ дан CodingWithSpike 27 November 2019 в 22:18
поделиться

IList

Не существует способа определить общую коллекцию, которая может принимать любой вкус вашего общего класса... т.е. IList. Общие классы - это только короткий путь для разработчика, чтобы сэкономить на написании кучи повторяющегося кода, но во время компиляции каждый вкус общего класса преобразуется в конкретный. Например, если у вас есть MyClass, MyClass, MyClass, то компилятор создаст 3 отдельных и разных класса. Единственный способ сделать то, что вы хотите - это иметь интерфейс для вашего generic.

public interface IMyGeneric {
    Type MyType { get; set;}    
}

class MyGeneric<T> : IMyGeneric {

    public MyGeneric() {
        MyType = typeof(T);
    }

    public Type MyType {
        get; set;
    }
}

и тогда вы можете сказать

IList<IMyGeneric> list = new List<IMyGeneric>();
list.add(new MyGeneric<string>());
list.add(new MyGeneric<int>());
1
ответ дан 27 November 2019 в 22:18
поделиться

Вы хотите иметь коллекцию MyClass, для которой значение параметра типа T отличается в каждом экземпляре. Это невозможно в .NET; в ней нет эквивалента подстановочного знака Java (?). Вместо этого нужно создать негенерический базовый класс или интерфейс, который может реализовать MyClass. Например:

public interface IMyClass {
  object Value { get; set; }
}
public class MyClass<T> : IMyClass {
  public T Value { get; set; }
  object IMyClass.Value {
    get { return Value; }
    set { Value = (T)value; }
  }
}
List<IMyClass> m = new List<IMyClass> { new MyClass<string>(), new MyClass<int> };
3
ответ дан 27 November 2019 в 22:18
поделиться

У меня есть интерфейсы для большинства моих общих типов с "Untyped" членами:

private interface IMyClass
{
    object UntypedValue { get; }
}

private class MyClass<T> : IMyClass
{
    T Value { get; set; }

    object UntypedValue { get { return Value; } }
}

Вы также можете сделать это с помощью явной реализации интерфейса, но, на мой взгляд, гораздо проще использовать отдельное имя. (Есть также несколько подсказок CA по явной реализации интерфейса)

4
ответ дан 27 November 2019 в 22:18
поделиться

Вы захотите определить базовый класс для MyClass, тогда ваши коллекции будут List базового класса. Ex:

void Main()
{
 var a = new MyClass<string>();
 var b = new MyClass<int>();
 var c = new List<MyBase>();
 c.Add(a);
 c.Add(b);

}

public class MyBase { }
// Define other methods and classes here
public class MyClass<T> : MyBase {
public T Value { get; set;}
}
3
ответ дан 27 November 2019 в 22:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: