4

リポジトリ用にこのインターフェースを作成しました。

public interface IRepository<T, in TKey> where T: class
{
    IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
    IEnumerable<T> FindAll();
    T FindSingle(TKey id);
    void Create(T entity);
    void Delete(T entity);
    void Update(T entity);
}

このFindSingleメソッドは、主キーの検索に使用される ID を受け入れます。を使用するinことで、参照型を as としてのみ渡すことができると予想していましたTKey。好奇心から、具象クラスを作成して int として指定することにしたので、例外を確認できました。

MSDNを調べたところ、これは機能しないと指定されています

ジェネリック型パラメーターの共変性と反変性は、参照型ではサポートされていますが、値型ではサポートされていません。

作成したクラスはこんな感じ

public class ProjectRepository : IRepository<Project,int>
{
    public IEnumerable<Project> Find(Expression<Func<Project, bool>> predicate)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<Project> FindAll()
    {
        throw new NotImplementedException();
    }

    public Project FindSingle(int id)
    {
        throw new NotImplementedException();
    }

    public void Create(Project entity)
    {
        throw new NotImplementedException();
    }

    public void Delete(Project entity)
    {
        throw new NotImplementedException();
    }

    public void Update(Project entity)
    {
        throw new NotImplementedException();
    }
}

TKey値の型として指定したビルドで例外が発生しなかったのはなぜですか? また、パラメータから を削除するinと、何が失われますか? MSDN のドキュメントには、反変性により派生型の少ない型を使用できると書かれていますが、それを削除するinことで、まだジェネリックであるため、任意の型を渡すことができます。

これは、反分散と共分散に関する理解の欠如を示している可能性がありますが、少し混乱しています。

4

4 に答える 4

6

値型はすべて封印されているため、共分散と反分散はあまり意味がありません。ドキュメントからは明らかではありませんがstruct、共/反変型として a を使用することは有効ですが、常に役立つとは限りません。あなたが参照しているドキュメントは、以下が無効であることを参照している可能性が最も高いです:

public struct MyStruct<in T>

反変性とは、次の例のようなことができることを意味します。

IRepository<string, Base> b = //something
IRepository<string, Derived> d = b;

から派生するものは何もないためint、 を使用できますが、IRepository<string, int>としてのみ使用できますIRepository<string, int>

IEnumerable<T>共分散とは、共変であるisなど、逆のことができることを意味しますout T。次のことができます。

IEnumerable<Derived> d = //something
IEnumerable<Base> b = d;

TKeyと の両方をes (参照型) に制限しようとしている場合は、2 つ目の制限を含める必要がありTます。class

public interface IRepository<T, in TKey>
    where T : class
    where TKey : class
于 2013-08-07T12:08:52.967 に答える
2

Indeed, you are missing the whole point of co- and contravariance :-) It is about being able to assign a variable of a generic type to another variable of the same generic type but with differing generic type argument(s) that are related to the ones used in the source.
Depending on whether the generic type parameter is co- or contravariant, different assignments are allowed.

Assume the following interface:

public interface IRepository<in T>
{
    void Save(T value);
}

Additionally, assume the following interface along with a value type and a reference type that implement it:

public interface IBar
{
}

public struct BarValueType : IBar
{
}

public class BarReferenceType : IBar
{
}

Finally, assume two variables:

IRepository<BarReferenceType> referenceTypeRepository;
IRepository<BarValueType> valueTypeRepository;

Contravariance now means that you can assign an instance of IRepository<IBar> to the variable referenceTypeRepository, because BarReferenceType implements IBar.
The section from the MSDN you quote simply means that the assignment of an instance of IRepository<IBar> to valueTypeRepository is not legal, although BarValueType also implements IBar.

于 2013-08-07T12:13:03.517 に答える
1

値型を使用してインターフェイスを実装することに問題はありません。たとえば、を に代入しようとしたときにのみエラーが発生しますIRepository<Project, object>IRepository<Project, int>次のコードでは、最後の割り当てがコンパイルされません。

public interface IContravariant<T, in TKey> where T : class
{
    T FindSingle(TKey id);
}
public class objCV : IContravariant<Project, object>
{
    public Project FindSingle(object id)
    {
        return null;
    }
    public static void test()
    {
        objCV objcv = new objCV();

        IContravariant<Project, Project> projcv;
        IContravariant<Project, int> intcv;

        projcv = objcv;
        intcv = objcv;
    }
}
于 2013-08-07T12:15:29.033 に答える
0

In this article, they are telling us that the type parameter is treated as invariant by the compiler:

Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.

From: http://msdn.microsoft.com/en-us/library/dd799517.aspx

于 2013-08-07T12:13:31.077 に答える