Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I specify a 'supertype' relation in C# generic constraints?

I have a collection class with an Equals method that I want to pass in a method to do equality checking between each item. Furthermore, I want to allow the delegate type to operate on superclasses of T as well as T itself:

public delegate bool EqualityComparer<T>(T x, T y);

public class Collection<T>
{
    //...

    public bool Equals<U>(Collection<T> other, EqualityComparer<U> eq) where T : U
    {
        // code using eq delegate to test equality between
        // members of this and other collection
    }
}

Unfortunately, the compiler borks over this ('Collection.Equals()' does not define type parameter 'T'). Is there any way of specifying this type of constraint/operation?

like image 809
thecoop Avatar asked Jul 27 '09 14:07

thecoop


People also ask

Can a supertype also be a subtype?

A supertype can have one or more subtypes, and a subtype can have one or more supertypes. A supertype can be a subtype of some other supertype, and a subtype can be a supertype of some other subtype.

Can a subtype have a relationship?

We say that a supertype's relationships are inherited by its subtypes. The converse is not true: if the model specifies specifically that a subtype participates in a relationship, then its siblings (other entity types that are subtypes of the same supertype) and its supertype do not participate in that relationship.

What is Supertype relationship?

A supertype is a generic entity type that has a relationship with one or more subtypes. A subtype is a sub-grouping of the entities in an entity type that is meaningful to the organization and that shares common attributes or relationships distinct from other subgroups.

Can a subtype have a primary key?

The subtypes will have the same primary key as their supertype.


2 Answers

No, I'm afraid you can't specify a constraint like that. (I've wanted it too on occasion.)

You could write a static generic method with two type parameters in a non-generic class though:

public delegate bool EqualityComparer<T>(T x, T y);

public class Collection
{
    public static Equals<T, U>(Collection<T> first,
                               Collection<T> second,
                               EqualityComparer<U> comparer) where T : U
    {

    }
}

and you could even make that call an instance method on the generic class if you like:

// Implementing the static method:
return first.Equals(second, new EqualityComparer<T>(comparer));

where the collection's instance method would just be:

public bool Equals(Collection<T> other, EqualityComparer<T> eq)
{
    // ...
}

This uses the contravariance available for creating delegates from C# 2 onwards.

like image 154
Jon Skeet Avatar answered Nov 11 '22 13:11

Jon Skeet


As Jon said you cannot reference the T within the constrain in that way since it is declared at the class level.

If you can write the method without access to the private state of the collection (or with their being internal) then you can rewrite like so:

public class Collection<T>
{
    ...
}

public static class CollectionExtentions
{
    public static bool Equals<T,U>(
            this Collection<T> first, 
            Collection<T> other, 
            EqualityComparer<U> eq) where T : U
    {
            ... // legal to use eq here on the T values with collections
    }
}

Incidentally I suggest you use Func<T,T,bool> rather than your own named delegate

like image 37
ShuggyCoUk Avatar answered Nov 11 '22 12:11

ShuggyCoUk