Использование обобщений в интерфейсах - PullRequest
5 голосов
/ 02 июня 2009

Как мне разрешить мой CookieData быть универсальным в следующем коде? Я получаю ошибку во время компиляции при объявлении ICookieService2.

public struct CookieData<T>
{
    T Value { get; set; }
    DateTime Expires { get; set; }
}

public interface ICookieService2: IDictionary<string, CookieData<T>>
{
   // ...
}

Моя ошибка:

Не удалось найти тип или имя пространства имен 'T' (отсутствует директива using или ссылка на сборку?)

Я хочу, чтобы ICookieService2 вставил в него общие данные. Спасибо!

Редактировать Разве это не запирает меня в один T для строительства любого ICookieService2?

Редактировать 2 Я пытаюсь сделать следующее:

CookieData<int> intCookie = { Value = 27, Expires = DateTime.Now };
CookieData<string> stringCookie = { Value = "Bob", Expires = DateTime.Now };

CookieService2 cs = new CookieService2();
cs.Add(intCookie);
cs.Add(stringCookie);

Ответы [ 8 ]

7 голосов
/ 02 июня 2009

Похоже, у вас есть 3 варианта здесь

Сделать ICookieService2 универсальным

public interface ICookieService2<T> : IDictionary<string, CookieData<T> {
...
}

Создайте неуниверсальный базовый класс для CookieData и используйте его в интерфейсе

public interface ICookieData {}
public class CookieData<T>: ICookieData{}
public interface ICookieService2 : IDictionary<string, ICookieData> {}

Выберите конкретную реализацию

public interface ICookieService : IDictionary<string, CookieData<int>> {}
4 голосов
/ 02 июня 2009

Вы также должны сделать ICookieService2 общим:

public interface ICookieService2<T>: IDictionary<string, CookieData<T>>
{
   // ...
}
2 голосов
/ 02 июня 2009

ОК, вот что вы хотите:

public interface ICookieDataBase
{
    DateTime Expires { get; set; }
}

public struct CookieData<T> : ICookieDataBase
{
    public T Value { get; set; }
    public DateTime Expires { get; set; }
}

public class ICookieService : IDictionary<string, ICookieDataBase>
{
    // ...
}

public void DoWork()
{
    var intCookie =
        new CookieData<int> { Value = 27, Expires = DateTime.Now };

    var stringCookie =
        new CookieData<string> { Value = "Bob", Expires = DateTime.Now };

    ICookieService cs = GetICookieService();
    cs.Add(intCookie);
    cs.Add(stringCookie);
}
1 голос
/ 02 июня 2009

Для этого необходим неуниверсальный интерфейс:

public interface ICookieData
{
  // you need this to get the value without knowing it's type
  object UntypedValue { get; }
  // whatever you need additionally ...
  Type DataType { get; } 

  DateTime Expires { get; set; }
}

public struct CookieData<T> : ICookieData
{
    // ICookieData implementation
    public object UntypedValue { get { return Value; } }
    public Type DataType { get { return typeof(T); } }
    public DateTime Expires { get; set; }

    // generic implementation
    T Value { get; set; }
}

public interface ICookieService2: IDictionary<string, ICookieData>
{
   // ...
}

CookieData<int> intCookie = { Value = 27, Expires = DateTime.Now };
CookieData<string> stringCookie = { Value = "Bob", Expires = DateTime.Now };

CookieService2 cs = new CookieService2();
cs.Add(intCookie);
cs.Add(stringCookie);
1 голос
/ 02 июня 2009

Я думаю, что вы хотите:

public interface ICookieService2<T>: IDictionary<string, CookieData<T>>
{
   // ...
}

В настоящее время ICookieService2 не является универсальным, поэтому T не определено.

Это позволяет создавать классы * ICookieService2<string> или ICookieService2<int> и т. Д.

EDIT: Отвечая на ваш последний запрос, я думаю, что это действительно зависит от того, что именно вам нужно. Тем не менее, что-то вроде этого может работать для вас.

public interface ICookieData
{
    object Value {get;} // if you need to be able to set from CookieService, life gets harder, but still doable.
    DateTime Expires {get;}
}

public struct CookieDate<T> : ICookieData
{
    T Value {get;set;}
    DateTime Expires {get;set;}

    object ICookieData.Value
    {
        get
        {
            return Value;
        }
    }
}

Тогда CookieService может быть или иметь Список, и вы сможете добавлять и CookieData, и CookieData. Если вам нужно написать (установить) из CookieService, его немного сложнее, и, возможно, лучше не использовать дженерики. Но если вам просто нужно получить CookieData, это может сработать для вас.

0 голосов
/ 02 июня 2009

Вы можете попробовать

public struct CookieData<T>
    where T : Object
{
    T Value { get; set; }
    DateTime Expires { get; set; }
}

Таким образом, все экземпляры T будут вынуждены иметь базовый тип Object. (почти все в C # (например, int == System.Integer и т. д.).

0 голосов
/ 02 июня 2009

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

CookieData нельзя передать как CookieData они на самом деле разные типы, универсальные типы не связаны и не могут быть переданы или переданы как одинаковые. Создание ICookieService2 как открытого универсального (то есть ICookieService2 ) не решает проблему, потому что тогда у вас будет другой тип ICookieService2 для каждого другого типа, и все они будут в другом словаре.

Вы можете создать интерфейс ICookieData и реализовать его в CookieData и использовать ICookieData для хранения элементов в словаре (как уже предложил Стефан).

Вы можете делать то, что вы хотите в C # 4.0 (с некоторыми ограничениями). Есть статья об этом здесь , до тех пор, пока вы не передадите ее как неуниверсальный тип, общий для них, такой как интерфейс, или просто укажите параметр value как объект в словаре, потому что вы нам придется использовать его в любом случае, если вы используете примитивы в качестве аргументов типа.

0 голосов
/ 02 июня 2009

не уверен насчет C #, но Java может также объявить ваш ICookieService2 как параметр <T> или указать <T> для чего-то конкретного в CookieData.

...