3

我想在另一个泛型类型中使用泛型类型。

但得到以下异常:

该类型'MockManagers.ToPos'不能用作'Res'泛型类型或方法中的类型参数'MockManagers.IMockManager<Req,Res>'。没有从'MockManagers.ToPos'到的隐式引用转换'MockManagers.MockResponseObject<System.IComparable>'

我尝试了几个选项来解决这个问题,但没有任何运气。此参考建议将内部泛型类型作为参数传递给更高级别的泛型类型。这是唯一的解决方案吗?

代码:
我的界面:

/// <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}

对象实现:

/// <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; }
}
4

2 回答 2

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带有 setter 的内容:只要不是通过界面,您就可以设置内容。

通过所有这些更改,以下内容现在有效并且可以正常编译:

static IMockManager<MockRequestObject, ToPos> manager = null;
于 2012-06-25T15:16:04.717 回答
2

您可以声明ToPos为派生自MockResponseObject<IComparable>而不是MockResponseObject<byte[]>,然后Content使用新的类型隐藏该属性byte[]。但是,要使其正常工作,您需要包装 abyte[]和 implements的东西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);
        }
    }
}
于 2012-06-25T15:38:31.890 回答