C# - Generic Types in Method Signature - Why CS1503, "Cannot Convert from IThing to ns.IThing"?

Viewed 131

While trying to work out an adapter pattern for use in an EFCore application with C# 9 under Visual Studio 2019, I'd developed a method something like the HandleThing<IThing>(IThing otherThing) method, below

namespace ns {
  public interface IThing
    {

    }

    public class Thing : IThing
    {
        public Thing(IThing thing)
        {
        }
    }

    public class ThingHandler
    {
        public void HandleThing<IThing>(IThing otherThing)
        {
            var entityThing = new Thing(otherThing);
        }
}

Subsequently, I'm presented with an error in the HandleThing<IThing> definition, at the 'otherThing' argument to the Thing constructor: "CS1503: Argument 1: Cannot convert from 'IThing' to 'ns.IThing'".

While VS recommends a cast such as the following, and that appears to work out at this point, I'm not certain I understand why this error is occurring, or why the cast would be needed.


    public class ThingHandler
    {
        public void HandleThing<IThing>(IThing otherThing)
        {
            var entityThing = new Thing((ns.IThing)otherThing);
        }
    }

Updating it to the following, it also eliminates a warning about nullability


    public class ThingHandler
    {
        public void HandleThing<IThing>(IThing otherThing)
            where IThing: notnull
        {
            var entityThing = new Thing((ns.IThing)otherThing);
        }
    }

It was my impression that the IThing type in the initial HandleThing<IThing>(IThing otherThing) signature would represent the IThing interface type that I'd already declared.

Is something getting lost across the generics in the definition?

1 Answers

The problem is the generic parameter was unconstrained.

Your generic parameter declaration <IThing> was a little skewed (which was likely confusing). Use T, and then constrain by Ithing

What you had

public void HandleThing<IThing>(IThing otherThing)

Instead, use standard T or T prefix so you don't get confused

public class ThingHandler
{
   public void HandleThing<T>(T otherThing) where T : IThing
   {
      var entityThing = new Thing(otherThing);
   }
}
Related