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>(); 

ただし、これはインターフェースでのみ可能であり、特定の分散制約を満たす場合にのみ可能です。そのようなインターフェースの1つがインターフェースです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;

では、これをどのように修正しますか?ここに1つのアイデアがあります。

まず、使用できないので使用できませbyte[]IComparablestring例として使用しましょうが、このインターフェースを実装する他の適切なものを見つける必要があります。

次に、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;
于 2012-06-25T15:16:04.717 に答える
2

の代わりにToPos派生元として宣言することもできますが、その場合は、タイプの新しいプロパティでプロパティを非表示にします。ただし、これを機能させるには、をラップして実装するものが必要です。例えば:MockResponseObject<IComparable>MockResponseObject<byte[]>Contentbyte[]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);
        }
    }
}
于 2012-06-25T15:38:31.890 に答える