2012-06-25 3 views
3

Я хотел бы использовать общий тип в другом родовом типе.Общий тип как общий тип

, но получает следующее исключение:

'MockManagers.ToPos' Тип не может быть использован в качестве параметра 'Res' типа в универсальном типе или методе 'MockManagers.IMockManager<Req,Res>'. Нет никакого неявного ссылочного преобразования от 'MockManagers.ToPos' до 'MockManagers.MockResponseObject<System.IComparable>'.

Я попробовал несколько вариантов, чтобы решить эту проблему без везения. Это reference предлагает передать внутренний общий тип как параметр для более высокого уровня общего типа. это единственное решение?

Код:
Мой Интерфейс:

/// <summary> 
/// Represents IMockManager for mock object creation object. 
/// </summary> 
/// <typeparam name="Req">The request object Type.</typeparam> 
/// <typeparam name="Res">The response object type.</typeparam> 
public interface IMockManager<Req, Res> 
    where Req : MockRequestObject 
    where Res : MockResponseObject<IComparable> 
{...//interface definitions} 

объекты implementatation:

/// <summary> 
/// Represents Mock response for a request object 
/// </summary> 
public class ToPos : MockResponseObject<byte[]> 
{... //implementation} 

public class MockBaseObject 
{ 
    public int Id { get; set; } 
} 

public class MockResponseObject<T> : MockBaseObject 
{ 
    /// <summary> 
    /// The response content. 
    /// </summary> 
    public T Content { get; set; } 

    /// <summary> 
    /// Res creation date. 
    /// </summary> 
    public DateTime CreationDate { get; set; } 
} 
+1

Является ли 'byte []' определенно 'IComparable'? Я бы не подумал, что их будет много. Если вы удалите это ограничение для 'Res', это сработает? – Rup

+0

имеют ту же проблему, что и удаление байт [] и использование байта –

+0

Пожалуйста, изучите историю изменений - я просмотрел код в указанной области, чтобы он действительно имел смысл (потому что вещи, которые выглядят как разметка, такие как '' angle скобки становятся скрытыми). Я не делаю этого снова, но, пожалуйста, сделайте это самостоятельно. –

ответ

3

Проблема здесь в том, что вы хотите родовое дисперсию по классу. C# поддерживает только общую дисперсию на интерфейсах.

Вот упрощенная версия того, что вы, кажется, хотят работать:

// Works fine: "string" is compatible with "IComparable" 
IComparable a = new string('a', 5); 

// Error: "List<string>" is not compatible with List<IComparable>" 
List<IComparable> b = new List<string>(); 

Это возможно только для интерфейсов, однако, и только тогда, если они удовлетворяют определенные ограничения дисперсии. Одним из таких интерфейсов является IEnumerable<out T> интерфейс:

// Works fine: IEnumerable is covariant 
IEnumerable<IComparable> c = new List<string>(); 

// Similarly, IEnumerable<string> is compatible with IEnumerable<IComparable>: 
IEnumerable<string> d = null; 
IEnumerable<IComparable> e = d; 

Так как же это исправить? Вот одна идея.

Во-первых, вы не можете использовать byte[], так как это не IComparable. Давайте используем в качестве примера string, но вам нужно найти что-то еще подходящее для реализации этого интерфейса.

Во-вторых, сделать MockResponseObject интерфейсом. Кроме того, сделать его коварианты в T:

public interface IMockResponseObject<out T> 
{ 
    T Content { get; } 
    DateTime CreationDate { get; set; } 
} 

Для того, чтобы это работало, Contentне может быть устанавливаемое через интерфейс.

Последнее, обновить остальную часть кода, чтобы использовать этот интерфейс:

interface IMockManager<Req, Res> 
    where Req : MockRequestObject 
    where Res : IMockResponseObject<IComparable> 
{ 
} 

public class ToPos : MockBaseObject, IMockResponseObject<string> 
{ 
    public string Content 
    { 
     get { throw new NotImplementedException(); } 
     set { throw new NotImplementedException(); } 
    } 

    public DateTime CreationDate 
    { 
     get { throw new NotImplementedException(); } 
     set { throw new NotImplementedException(); } 
    } 
} 

Заметим, что ToPos все еще имеет Content с установщиком: вы можете установить содержание, пока он не через интерфейс.

С учетом всех этих изменений, следующие в настоящее время действует и отлично компилируется:

static IMockManager<MockRequestObject, ToPos> manager = null; 
2

Вы могли бы просто объявить ToPos как производное от MockResponseObject<IComparable> вместо MockResponseObject<byte[]>, но затем скрыть Content свойство с новым типа byte[]. Однако для этого вам нужно что-то, что обертывает byte[] и реализует IComparable. Например:

public class ByteArrayComparable : IComparable 
{ 
    public byte[] Data { get; private set; } 
    public ByteArrayComparable(byte[] data) { Data = data; } 

    // Implement IComparable.CompareTo() method here! 
    public int CompareTo(object obj) { ... } 
} 

public class ToPos : MockResponseObject<IComparable> 
{ 
    public new byte[] Content 
    { 
     get 
     { 
      if (base.Content == null) 
       return null; 
      return ((ByteArrayComparable) base.Content).Data; 
     } 
     set 
     { 
      base.Content = value == null ? null : new ByteArrayComparable(value); 
     } 
    } 
} 
+0

Благодарим вас за ответ. –

Смежные вопросы