简体   繁体   中英

Problem implementing a generic method in a generic type which inherits from a non-generic interface

I have a non-generic interface with two generic method signatures.

interface IDataContainer
{
    T GetValue<T>();
    void SetValue<T>(T value);
}

Then I have a generic class that implements IDataContainer

public class DataContainer<T>: IDataContainer
{
    private T _value;

    #region IDataContainer Members

    public T GetValue<T>()
    {
        return _value;
    }

    public void SetValue<T>(T value)
    {
        _value = value;
    }

    #endregion
}

I am getting an error about not being able to implicitly convert type T to T on the GetValue and SetValue methods that were implemented.

Is there a way to solve this? Some sort of type constraint for equality? Is there a better way?

I know that I could just make IDataContainer generic by making it IDataContainer<T> , but then I could not have a List of IDataContainers when T is not always the same type.

Your problem is that the compiler sees two different types. T in the scope of IDataContainer is not the same T as in the scope of your generic method, and thus the compiler complains.

Because your container holds an instance of T, I think your interface should also have the type-parameter T (not just a method-scope generic parameter).

Your current interface actually promises (remember, an interface is a contract), to be able to deliver a value of T for any T - surely that is not what you want?

The intent of your code would be nicely captured in a generic interface:

interface IDataContainer<T> {
  T GetValue();
  void SetValue(T value);
}

So why do you have a non-generic interface with generic methods?

The problem with the generic methods is that the type parameter is not the same , although they have the same name.

To have a list of data containers for when T is not the same, just have a non-generic base interface for your generic interface:

interface IDataContainer { }

interface IDataContainer<T> : IDataContainer { 
  ...
}

Then you can have a list of the non-generic data container.

Those two methods mean two different things. In IDataContainer, you specify a generic method. This can be called with any type. In DataContainer , you specify methods which take the specific type parameter specified in the class. IDataContainer 's contract is not satisfied by DataContainer . You should change IDataContainer so that it's generic.

To make it more clear, consider IDataContainer in isolation. The following code should be legal regardless of the concrete container returned by getContainer()

IDataContainer ctr = getContainer();
String x = ctr.getValue<String>();

However, if getContainer looked like the following, then that code would clearly break if what you had was legal:

public IDataContainer getContainer() {
    return new DataContainer<Foo>();
}

The fundamental problem you have is that if you have DataContainers for different types, then the contracts for those DataContainers are just fundamentally different. A DataContainer<Foo> has a GetValue that gives you a Foo , while a DataContainer<Bar> has a GetValue that gives you a Bar . If there's a superclass of both Foo and Bar, then you can use that, otherwise, you're going to be casting, because you simply can't guarantee type-safety if you toss them both into a list together.

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