2012-06-25 45 views
3

我想在另一通用类型中使用通用类型。通用类型作为通用类型

但得到以下情况除外:

类型'MockManagers.ToPos'不能用作在通用类型或方法'MockManagers.IMockManager<Req,Res>'类型参数'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

时有同样的问题请检查编辑历史记录 - 我在引用区域标记了代码,以便它确实有意义(因为看起来像标记的东西,例如''角括号变成隐藏)。我不再做,但请自己做。 –

回答

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仍然有一个setter一个Content:只要它不是通过界面可以设置内容。

伴随着这些变化,以下是目前有效的和精细的编译:

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

你可以只声明ToPosMockResponseObject<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

谢谢您的回复。 –