0

I have a couple of interfaces like this:

public interface IAppointment<TUser> where TUser : IUser
{
    string TeamName { get; set; }
    TUser Host { get; set; }
    string HostNameForGuest { get; }
    bool HostNameVisible { get; set; }
}

and

public interface IUser
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

The use of a generic for the IAppointment interface is because one of the classes where I'm implementing it is auto-generated by Entity Framework and I can't change the return type of the Host property from User (the name of the database entity it describes) to IUser. This implementation is shown below. The other properties specified in the interface are already present in the EF-generated partial class of the same name.

public partial class Appointment : IAppointment<User>
{   
    public string HostNameForGuest
    {
        get
        {
            return AppointmentHelper.HostNameForGuest(this);
        }
    }
}

As you can see, I'm trying to get the value for the HostNameForGuest property from a function, the reason being that I want to reuse the logic for deriving the value in multiple other classes which implement the same interface. The function looks like this:

public static string HostNameForGuest(IAppointment<IUser> appointment)
{
    return appointment.HostNameVisible ? $"{appointment.Host.FirstName} appointment.Host.LastName}" : appointment.TeamName;
}

The problem I have is that the above code throws an IntelliSense error for the line

return AppointmentHelper.HostNameForGuest(this);

Underlining this and saying:

Argument 1: cannot convert from 'AppointmentBooking.DAL.Appointment' to 'AppointmentBooking.Global.Interfaces.IAppointment<AppointmentBooking.Global.Interfaces.IUser>'

I understand the error but I don't know how to fix it. I realise this is just exposing a shortcoming in my knowledge of generics, which are not something I've used often, and it's probably just a case of expressing the parameters correctly, but no combination I've tried has worked so far. I've tried modifying the line to:

return AppointmentHelper.HostName(this<User>);

and

return AppointmentHelper.HostName(this<IUser>);

both of which yield the error

'User' is a type, which is not valid in the given context

('User' is 'IUser' in the error message for the second example, obviously).

So what's the correct way to pass the class that implements IAppointment<IUser> as a parameter to the function which accepts the interface type as a parameter?

EDIT

The questions which have been suggested as duplicates for this all seem to boil down to people trying to convert a derived class to its base class. I don't think that's what I'm doing, though I'm quite prepared to be told I'm wrong.

For a start, I'm not inheriting a class, I'm implementing an interface.

Secondly, I don't have any complaints from the compiler when I take out the IUser interface. This doesn't throw the error:

public interface IAppointment
{
    string TeamName { get; set; }
    string HostNameForGuest { get; }
    bool HostNameVisible { get; set; }
}
public partial class Appointment : IAppointment
{   
    public string HostNameForGuest
    {
        get
        {
            return AppointmentHelper.HostNameForGuest(this);
        }
    }
}
public static string HostNameForGuest(IAppointment appointment)
{
    return appointment.HostNameVisible ? $"{appointment.Host.FirstName} appointment.Host.LastName}" : appointment.TeamName;
}

If the problem was me trying to convert the "derived" Appointment class (I don't know if "derived" is the right term for a class that implements an interface or if it refers specifically to a class that inherits another class) to the "base" class IAppointment (again, it's an interface, not a base class) then I'd still expect to get the same error. Wouldn't I..?

Philip Stratford
  • 4,513
  • 4
  • 45
  • 71
  • IMO I don't think generics are offering you any benefits here, only needless complicating things (unless it's doing some other heavy lifting not shown in your post). Why not make `IAppointment` non-generic and let the `Host` property be of type `IUser`? – Luke Oct 18 '22 at 14:20
  • Looks like you should be able in this case to declare `interface IAppointment where ...` – Damien_The_Unbeliever Oct 18 '22 at 14:21
  • 1
    @Damien_The_Unbeliever unfortunately the compiler will complain about `TUser Host` being in an invariant position. – Mong Zhu Oct 18 '22 at 14:24
  • @Luke The generic was necessary because, without it, the compiler complained that the property `Host` in my EF-generated class did not have a return type of `IUser`. Which it doesn't - its return type is `User` - but I can't change the EF-generated class. Adding the generic in this way got around that. – Philip Stratford Oct 18 '22 at 14:52

0 Answers0