0

Given the following interfaces, I don't understand why the second method defined on ITransactionConsumer will not compile. The compiler complains that it is not convertable to ITransaction<IUser> - but there is a generic constraint that TUser is an IUser..?

    public interface ITransactionConsumer
    {
        //fine
        PaymentSession<TTransaction> ConsumeTransaction<TTransaction>( TTransaction transaction ) 
            where TTransaction : ITransaction<IUser>;

        //compile error - TTransaction is not convertable to ITransaction<IUser>
        PaymentSession<TTransaction> ConsumeTransactionWithTUser<TTransaction, TUser>(TTransaction transaction) 
            where TTransaction : ITransaction<TUser> where TUser : IUser;
    }

    public class PaymentSession<TTransaction>
        where TTransaction : ITransaction<IUser>
    {
    }

    public interface ITransaction<out TUser>
        where TUser : IUser
    {
        TUser User { get; }
        string Id { get; }
    }

    public interface IUser
    {
        string Name { get; }
    }
2
  • 1
    It looks like you need to add a class constraint to TUser, i.e. where TUser class, IUser. Commented Sep 26, 2017 at 13:42
  • I get a different compile error: Severity Code Description Project File Line Suppression State Error CS0314 The type 'TTransaction' cannot be used as type parameter 'TTransaction' in the generic type or method 'PaymentSession<TTransaction>'. There is no boxing conversion or type parameter conversion from 'TTransaction' to 'ITransaction<IUser>'. Commented Sep 26, 2017 at 13:44

1 Answer 1

1

Can you replace your offending line with this?

  PaymentSession<TTransaction> ConsumeTransactionWithTUser<TTransaction, TUser>(TTransaction transaction)
     where TTransaction : ITransaction<TUser>, ITransaction<IUser> where TUser : IUser;

Edit: Since that worked, the most correct approach (for what I expect you intended with your code) would be to use the syntax you used in your first ConsumeTransaction declaration:

  PaymentSession<TTransaction> ConsumeTransactionWithTUser<TTransaction, TUser>(TTransaction transaction)
     where TTransaction : ITransaction<IUser>;

The mistake you made involves your PaymentSession return value. Your PaymentSession class expresses a constraint on the type argument it can accept. You defined that type argument as TTransaction and then specified that TTransaction must implement an interface ITransaction that has IUser as its type parameter. But you then tried to declare a function ConsumeTransactionWithTUser that returns a type of PaymentSession where TTransaction is a type that implements IUser. A type that implements an interface is not the same as the interface itself! PaymentSession's type must be IUser--that is the constraint you specified, which is why the compiler complained: ITransaction< TUser > is not the same as ITransaction< IUser >.

To wrap up: Your constraint in the PaymentSession class requires the generic type to be of type ITransaction < IUser >--that's more restrictive than saying that PaymentSession requires the generic type to be of generic type ITransaction that accepts a type that implements IUser.

Sign up to request clarification or add additional context in comments.

3 Comments

That works! Still a little confused as to why that's necessary but that's what I need. Thank you, will mark as correct.
A good answer should include explanation as well as code. Otherwise nobody learns anything.
Working on explanation--will provide at next break.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.