1

I'm working in C#. I created an interface in my code which is called EntityInterface. I wrote this function:

private void Save(List<EntityInterface> entities)
{ ... }

Elsewhere in my code, I have a variable which is defined as List<Job>. The Job class is a class that implements EntityInterface.

I cannot pass my list of Job objects to the Save method. The compiler complains that the parameter is of the wrong type, because List<Job> is not the same as List<EntityInterface>.

I need to modify the function to express the idea that the parameter can be a "list of any object that implements EntityInterface". I have searched around but can't find an example of how to do this.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Flarosa
  • 1,287
  • 1
  • 13
  • 27
  • Are you looking for [generics](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/)? Or [generic constraints](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters)? – Jonathon Chase Jan 31 '19 at 23:59
  • 1
    Please paste the definition of what you are trying to pass, and the actual types of what your method is. – TheGeneral Feb 01 '19 at 00:02
  • Not exactly sure what you are asking (as ` extends Type >?` is not C# concept), but you should re-read why you can't [convert list of derived type to list of base type](https://stackoverflow.com/questions/16966961/cannot-convert-from-listderivedclass-to-listbaseclass) as you probably missed some info there. – Alexei Levenkov Feb 01 '19 at 00:06
  • 5
    Try `private void Save(List entities) where T : EntityInterface`. – Enigmativity Feb 01 '19 at 00:07
  • You’re talking about covariance but I agree with @enigmativity – Moho Feb 01 '19 at 00:23
  • If you don't need to _add_ to the list you could just define it as `Save(IEnumerable entities)` and you can then pass in a `List`. – D Stanley Feb 01 '19 at 01:54
  • ` extends Type>` (or `<* extend Type>` for other variant) is a Java generic constraint based on wildcard. The equivalent C# type is `where T: Type` because C# doesn't have use-site wildcard generic concept. – Tetsuya Yamamoto Feb 01 '19 at 02:32

1 Answers1

1

Your model should look something like this:

using System.Collections.Generic;

public interface IEntity
{
    void Save<T>(List<T> entities) where T : IEntity;
}

public class Job : IEntity
{
    void IEntity.Save<T>(List<T> entities) { }
}

public class TargetImpl : IEntity
{
    void IEntity.Save<T>(List<T> entities) { }
}

and as a test to step through:

using System.Collections.Generic;
using Xunit;

public class UnitTest1
{
    [Fact]
    public void Test1()
    {
        IEntity ientity = new TargetImpl();
        ientity.Save(new List<Job>());
    }
}

One caveat being the example above implements the IEntity interface explicitly (for brevity) as such child implementations must be explicitly referenced via that interface. For a similar but subtly different implementation you could also do:

public class Job : IEntity
{
    public void Save<T>(List<T> entities) where T : IEntity { }
}

public class TargetImpl : IEntity
{
    public void Save<T>(List<T> entities) where T : IEntity { }
}

and the test impl can (optionally) change to :

[Fact]
public void Test1()
{
    targetImpl ientity = new TargetImpl();
    ientity.Save(new List<Job>());
}
TheFastCat
  • 3,134
  • 4
  • 22
  • 32
  • 1
    Appreciate the comments and examples. The solution turned out to be pretty trivial. I changed List to IEnumerable. I guess that the compiler realizes you can't add items to a list via IEnumerable and so it lets the list be passed this way. – Flarosa Feb 02 '19 at 00:39