简体   繁体   中英

Covariant interface with contravariant interface as member property

I have an interface which defines a reader and a writer for any IFoo.

public interface IFoobarStore<out E>
 where E : class, IFoobar
{
    IFoobarReader<E> GetReader();
    IFoobarWriter<E> GetWriter();
}

IFoobarStore is covariant. IFoobarStore interacts with any derived IFoo. As such, any more derived IFoo should be assignable to a more derived IFoo type argument.

// DerivedFoobityStore.cs
public sealed class DerivedFoobityStore
 : IFoobarStore<MyFoobity>
{
    // implementation follows
}

If IFoobarStore were defined as being variant with IFoobarStore<E> instead of IFoobarStore<out E> , the following would produce compiler error CS0266.

IFoobarStore<IFoo> myGenericStore = new DerivedFoobityStore();

The reader is defined as covariant as well. It should allow reading derived IFoo objects from somewhere.

using System.Collections.Generic;
public interface IFoobarReader<out E>
 where E : class, IFoo
{
    IEnumerable<E> GetAll();
    IEnumerable<E> GetBy(params object[] vars);
    E GetSingle(object uniqueIdentifier);
}

IFoobarWriter exposes members used for standard CRUD operations on any IFoo.

public interface IFoobarWriter<in E>
 where E : class, IFoo
{
    void Add(E foo);
    int Delete(E foo);
    E Update(E foo);
}

Since every operation has a single argument of type E (any class derived from IFoo), IFoobarWriter must be flagged as contravariant.

When I compile my code I receive this error:

Invalid variance: The type parameter 'E' must be contravariantly valid on 'IFoobarStore<E>.GetWriter()'. 'E' is covariant.

How can I better refactor this code so it compiles successfully?

For the moment I got around it by refactoring IFoobarWriter to work with an object instead of an IFoo.

public interface IFoobarWriter<out E>
 where E : class, IFoo
{
    void Add(object foo);
    int Delete(object foo);
    object Update(object foo);
}

This renders the basic premise of IFoobarWriter obsolete.

The solution was to remove E as an acceptable argument for instance member methods of IFoobarWriter.

public interface IFoobarWriter<out E>
 where E : class, IFoo
{
    void Add(IFoo foo);
    int Delete(IFoo foo);
    object Update(IFoo foo);
}

By having Add, Delete, and Update accept IFoo they effectively limit the types they can work on (as opposed to setting the argument to object ) well enough for certain business requirements.

Having the type parameter E for IFoobarWriter remain covariant allows it to remain a part of the IFoobarStore interface.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM