user489041
user489041

Reputation: 28294

Function Declarations with Generics in C#

I have a function that is declared like so:

public static string MultiWhereToString(List<WhereCondition<T>> whereConditions)

I am trying to pass it a variable called whereAnd which is delcared like so:

private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();

WhereAndCondition is a sub class of WhereCondition. It is declared like so:

public class WhereAndCondition<T> : WhereCondition<T>, IConditional where T : DatabaseObject

My issue is, if I try to execute the following code:

private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();
MultiWhereToString(whereAnd);

I get the following error:

Error 3 Argument 1: cannot convert from 'System.Collections.Generic.List<BrainStorm.WhereAndCondition<T>>' to 'System.Collections.Generic.List<BrainStorm.WhereCondition<T>>'

Any ideas on why? I think it has to do with the generics of the WhereCondition classes.

Upvotes: 1

Views: 222

Answers (6)

Joe
Joe

Reputation: 82554

I would suggest using interfaces:

public static string MultiWhereToString(IEnumerable<ICondition<T>> whereConditions)

This would allow you a lot more freedom when calling this method.

Upvotes: 2

Kay
Kay

Reputation: 13146

Generics have to be known explicitly at compile time because they are generated.

Why not use:

private List<WhereCondition<T>> whereAnd = new List<WhereCondition<T>>();

So you can still add WhereAndCondition objects to whereAnd.

Upvotes: 2

McKay
McKay

Reputation: 12604

This appears to be a covariance / contravariance issue.

Simplified to this:

    public class WhereCondition
    {
    }

    public class WhereAndCondition : WhereCondition
    {
    }

    public class blah
    {
        public static void Blah()
        {
            List<WhereAndCondition> whereAnd = new List<WhereAndCondition>();
            MultiWhereToString(whereAnd);
        }

        public static string MultiWhereToString(List<WhereCondition> whereConditions)
        {
            return null;
        }
    }

It's not going to work, because the list of WhereAndConditions can't be cast to List of WhereConditions:

Imagine it this way. You've got a list of giraffes, and the method is asking for a list of animals.

Without knowing what they are going to do with the list animals (like try adding a horse) the types are incompatible, but if you change it to something like this:

        public static string MultiWhereToString(IEnumerable<WhereCondition> whereConditions)
        {
            return null;
        }

Then the variance can kick in, and give you what you're looking for.

Upvotes: 2

Johannes Kommer
Johannes Kommer

Reputation: 6451

You can replace the entire WhereCondition<T> in your MultiWhereToString method with another generic type which is restricted to WhereCondition<T>.

Replace:

public static string MultiWhereToString(List<WhereCondition<T>> whereConditions)

With:

public static string MultiWhereToString<TType>(List<TType> whereConditions) where TType: WhereCondition<T>

Or alternatively change:

private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();

to:

private List<WhereCondition<T>> whereAnd = new List<WhereCondition<T>>();

And let inheritance take care of the rest for you.

Upvotes: 2

Esoteric Screen Name
Esoteric Screen Name

Reputation: 6112

Your function is defined as taking a WhereCondition List, but you're passing it a WhereAndCondition List:

MultiWhereToString(List<WhereCondition<T>> whereConditions)

private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>(); 
MultiWhereToString(whereAnd); 

List variance has limited supported in .NET 4. See this question.

Upvotes: 2

millimoose
millimoose

Reputation: 39950

Given:

class A {}
class A : B {}

An object of List<B> is not an instance of List<A>. So you can't cast a List<WhereAndCondition> to a List<WhereCondition>. You could use:

MultiWhereToString(whereAnd.OfType<WhereCondition>().ToList());

(There might also be a solution involving the in and out variance annotations, but I'm not terribly familiar with them.)

Upvotes: 2

Related Questions