patrick
patrick

Reputation: 23

C# Can't cast to interface even though it inherits it

I have a small problem I can't seem to get working right. I currently have a list of IModelConverters like this:

public class ModelConverterList : List<IModelConverter<IDataCollection>>
{
}

And I am trying to add entries like this:

public static void AddModelConverter<T>(IModelConverter<T> converter) 
  where T: IDataCollection
{
    CheckForSetup();
    modelConverters.Add(converter);
}

CheckForSetup is a method checking if the list isn't null (along with some other unrelevant checks). This is the interface I want to cast to:

public interface IModelConverter<in T>: IConverter where T: IDataCollection
{
    ResponseData Activate(T documents, ServiceContext services, bool overrideIfNeeded = false);

    bool ContainsFile(T document, ServiceContext services);
}

However, it doesn't want to cast to this interface. I tried casting it to IModelConverter<T> and IModelConverter<IDataCollection>

The object I want to add has an abstract class that uses the interface, could this be why it isn't working?

I also thought about multiple references to it, but it doesn't seem like that's the case.

EDIT:

The error I get in the editor is this: "Argument 1: cannot convert from 'Extensions.Abstractions.Interfaces.IModelConverter' to 'Extensions.Abstractions.Interfaces.IModelConverter'"

And the class I want to add is this:

public class LanguageConverter : DocumentConverterCreatorBase<LanguageCollection>
{
protected override void ActivateDocument(LanguageCollection collection, ServiceContext services, bool overrideIfNeeded)
{
  ILocalizationService fs = services.LocalizationService;
  foreach (LanguageType language in collection.List)
  {
    if (fs.GetLanguageByIsoCode(language.CultureAlias) != null && overrideIfNeeded)
      fs.Delete(fs.GetLanguageByIsoCode(language.CultureAlias));

    if (fs.GetLanguageByIsoCode(language.CultureAlias) == null)  
      fs.Save(language.Construct(services));
  }
}

public override bool ContainsFile(LanguageCollection document, ServiceContext services)
{
  ILocalizationService ls = services.LocalizationService;
  foreach (LanguageType item in document.List)
  {
    if (ls.GetLanguageByIsoCode(item.CultureAlias) == null)
      return false;
  }
  return true;
}

}

And the abstract class is this:

public abstract class DocumentConverterCreatorBase<T>: IAssetConverter, IModelConverter<T>, IModelCreator where T : IDataCollection

The abstract class has two abstract methods for the methods in the interface.

The IDataCollection is nothing but a list of data. The interface is as follows:

public interface IDataCollection
  {
    int GetCount();
  }

Upvotes: 0

Views: 2127

Answers (1)

Enigmativity
Enigmativity

Reputation: 117027

The problem you're seeing is one of co-variance.

If you have these type definitions:

public class ModelConverterList : List<IModelConverter<IDataCollection>> { }
public interface IModelConverter<in T> : IConverter where T : IDataCollection { }
public interface IDataCollection { }
public interface IConverter { }

...then with this code:

private static ModelConverterList modelConverters = new ModelConverterList();

public static void AddModelConverter<T>(IModelConverter<T> converter) where T : IDataCollection
{
    modelConverters.Add(converter);
}

...you get the following error:

CS1503 Argument 1: cannot convert from 'IModelConverter<T>' to 'IModelConverter<UserQuery.IDataCollection>'

Even though we know that T inherits from IDataCollection, it isn't the same as saying that IModelConverter<T> inherits from IModelConverter<IDataCollection> - it doesn't. So there is no cast from IModelConverter<T> to IModelConverter<IDataCollection>.

This compiles:

public class ModelConverterList : List<IModelConverter<IDataCollection>> { }
public interface IModelConverter<out T> : IConverter where T : class, IDataCollection { }
public interface IDataCollection { }
public interface IConverter { }

private static ModelConverterList modelConverters = new ModelConverterList();

public static void AddModelConverter<T>(IModelConverter<T> converter) where T : class, IDataCollection
{
    modelConverters.Add(converter);
}

But I've changed the definition of IModelConverter from in T to out T and added a class constraint.

Upvotes: 3

Related Questions