4

I'm having some trouble figuring out how to require a class has extended an interface when working with generic objects. I find this to be difficult to explain, but I want to be able to require a class & an interface when creating my generic object.

I've created the simplest version of this that I can think of - hopefully that will explain my problem better than I can.

abstract class Base
{}
class Class1 : Base, IComparable<Base>
{
    public int CompareTo(Base other)
    {
        return GetHashCode().CompareTo(other.GetHashCode());
    }
}
class Class2 : Base, IComparable<Base>
{
    public int CompareTo(Base other)
    {
        return GetHashCode().CompareTo(other.GetHashCode());
    }
}
class Class3 : Base
{}
class Program
{
    // This list should only accept objects that extend (Base & IComparable<Base>)
    public static List<Base> BigList = new List<Base>();

    static void Main(string[] args)
    {
        Class1 c1 = new Class1();
        Class2 c2 = new Class2();
        Class3 c3 = new Class3();
        BigList.Add(c1);
        BigList.Add(c2);
        // This should not be allowed because Class3 does not extend IComparable<Base>
        BigList.Add(c3);

        Check(new Class1());
    }
    public static void Check(Base bb)
    {
        foreach (Base b in BigList)
        {
            // Assert that this is true
            IComparable<Base> c = (IComparable<Base>)b;

            if (c.CompareTo(bb) < 0)
                Console.WriteLine("Less Than");
            else if (c.CompareTo(bb) == 0)
                Console.WriteLine("Equal");
            else if (c.CompareTo(bb) > 0)
                Console.WriteLine("Greater Than");
        }
    }
}

As you can see from the inline comments in the code, I'd like the list BigList to require that the objects being added extend Base AND implements IComparable<Base>. This isn't really multiple inheritance though because it's only one class (and an interface).

Does anyone know of a way to do this?

EDIT

Thanks for the comments everyone. Basically the answers come in two flavors: Create an Intermediate class, or use List<IComparable<Base>>. #2 isn't an option because there is logic in Base that we do actually need. #1 is the most viable option, and the one that we are grudgingly going with. The concern with this approach is the amount of mess and complexity this will add in the actual class hierarchy.

Regardless if C# won't let us do what we want to do then we will have to do it with the intermediate classes. Thanks everyone.

4
  • 1
    What you want is not possible without creating your own data structure, refactoring your class hierarchy, or creating an Add() helper method. Why don't you make your BigList of type List<IComparable<Base>>()? Commented May 11, 2012 at 15:18
  • // This should not be allowed because Class2 does not extend IComparable<Base> >>> class Class2 : Base, IComparable<Base> er i hate to break it to you but class 2 does extend it ;) class three however does not Commented May 11, 2012 at 15:21
  • @Osiris: Pretty much sums up my thoughts. Commented May 11, 2012 at 15:22
  • You can't do it with List<Base>, you have to do it with List<IComparable> Commented May 11, 2012 at 15:22

4 Answers 4

7

What about this:

abstract class Base {
}

abstract class Intermediate : Base, IComparable<Base> {
}

class Class1 : Intermediate {
}

class Class2 : Intermediate {
}

class Class3 : Base {
}

public static List<Intermediate> BigList = new List<Intermediate>();
BigList.Add(new Class1()); // ok
BigList.Add(new Class2()); // ok
BigList.Add(new Class3()); // error

This, of course, is necessary only if you need to have classes implement Base but not IComparable<Base>, otherwise you could just declare Base as

abstract class Base : IComparable<Base> {
}
Sign up to request clarification or add additional context in comments.

Comments

0

Why don't you create another class inheriting base and implementing IComparable?

public class ComparableBase :Base, IComparable<Base>
{
....
}

class Class2 : ComparableBase 
{
    public int CompareTo(Base other)
    {
        return GetHashCode().CompareTo(other.GetHashCode());
    }
}

public static List<ComparableBase > BigList = new List<ComparableBase >();

Comments

0

If you set your BigList to be a List<IComparable<Base>> that should get the behavior your displaying in your Check method.

public static List<IComparable<Base>> BigList = new List<IComparable<Base>>();
static void Main(string[] args)
{
    Class1 c1 = new Class1();
    Class2 c2 = new Class2();
    Class3 c3 = new Class3();
    BigList.Add(c1);
    BigList.Add(c2);
    // This will now cause a compile error
    // BigList.Add(c3);

    Check(new Class1());
}

public static void Check(Base bb)
{
    foreach (IComparable<Base> c in BigList)
    {
        if (c.CompareTo(bb) < 0)
            Console.WriteLine("Less Than");
        else if (c.CompareTo(bb) == 0)
            Console.WriteLine("Equal");
        else if (c.CompareTo(bb) > 0)
            Console.WriteLine("Greater Than");
    }
}

Comments

0

IMO, implementation without an intermediate class can be done like so:

abstract class Base{}

class Class1 : Base, IComparable<Base>{}

class Class2 : Base, IComparable<Base>{}

class Class3 : Base{}

var BigList = new List<IComparable<Base>>();

BigList.Add(new Class1());
BigList.Add(new Class2());
BigList.Add(new Class3()); // error

And you can compare as:

public static void Check(Base BB){
 foreach (var c in BigList)
    {
        if (c.CompareTo(bb) < 0)
            Console.WriteLine("Less Than");
        else if (c.CompareTo(bb) == 0)
            Console.WriteLine("Equal");
        else if (c.CompareTo(bb) > 0)
            Console.WriteLine("Greater Than");
    }
}

1 Comment

But I could create a class that does not inherit from Base and that could be stored in the list: class NoBase : ICombarable<Base> {}. I think that defeats one of his conditions.

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.