Ms. Corlib
Ms. Corlib

Reputation: 5213

How can a class inherit from a parameterized version of itself?

I saw a C# class SomeClass that was defined like

public class SomeClass : IComparable<SomeClass>, IEquatable<SomeClass>
{
   // ... 
}

and I'm wondering how to translate that into English. The way I understand it seems logically impossible. How can a class inherit from a parameterized version of itself? Also, is this a common design pattern?

Upvotes: 10

Views: 1340

Answers (5)

Bav
Bav

Reputation: 11

Translated in "English" it means: "Boy (or girl), you'd better be type-safe when implementing those interfaces, especially IComparable. Otherwise, you'll have to perform type casting, which I guess you don't want"

See the code below. SomeClass implemented IComparable and IComparable. See differencies between implementations of CompareTo(object) and CompareTo(SomeClass).

namespace InterfacesStuff
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var someClass1 = new SomeClass {ComparedValue = 1};
            var someClass2 = new SomeClass {ComparedValue = 2};

            //someClassObject defined as SomeClass
            //object someClassObject = new SomeClass { ComparedValue = 2 };

            //someClassObject defined as anything else but SomeClass
            object someClassObject = 5;

            int comparisonSomeClassBySomeClass = someClass1.CompareTo(someClass2);

            int comparisonSomeClassByObject = someClass1.CompareTo(someClassObject);
        }
    }


    public class SomeClass : IComparable, IComparable<SomeClass>, IEquatable<string>, IEquatable<int>,
        IEquatable<double>
    {
        public int ComparedValue;

        public int CompareTo(object obj)
        {
            var presumedSomeClassObject = obj as SomeClass;

            if (presumedSomeClassObject != null)
            {
                if (ComparedValue <= ((SomeClass) obj).ComparedValue)
                    return -1;
            }

            return 0;
        }

        public int CompareTo(SomeClass other)
        {
            if (ComparedValue <= other.ComparedValue)
                return -1;

            return 0;
        }

        public bool Equals(double other)
        {
            throw new NotImplementedException();
        }

        public bool Equals(int other)
        {
            throw new NotImplementedException();
        }

        public bool Equals(string other)
        {
            throw new NotImplementedException();
        }
    }
}

Upvotes: 1

ThomasMX
ThomasMX

Reputation: 1822

The code you posted does not inherit from any class. It is implementing certain so-called Interfaces. How to translate that snippet: "I guarantee that SomeClass will be Comparable and equatable with other SomeClass instances. I will provide definitions in this class on how to do that."

About specializing a class from some other class... What you can do is something like this:

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Pet
    {
        protected string name;
        public Pet(String name)
        {
            this.name = name;
        }

    }

    class Dog : Pet
    {
        private List<String> tricks;
        public Dog(String name, List<String> tricks):base(name)
        {
            this.tricks = tricks;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<string> tricks = new List<string>();
            tricks.Add("sit");
            tricks.Add("jump");
            tricks.Add("bark");
            Dog puppy = new Dog("Fido", tricks);
        }
    }
}

Dog inherits from Pet. Dog calls Pet's constructor at creation. Whatever name you pass into Dog constructor, it will forward it to Pet constructor. Because what happens is that a subclass first calls the constructor of its superclass with the appropriate arguments. Then it runs its own constructor. Whatever is declared as public or protected in a class will be visible to its subclasses.

Therefore Dog will have name and also a list of tricks:

puppy object result

You achieve this kind of view with the "Locals" window.

I recommend that you read some tutorials on c# inheritance, interfaces and generics

Upvotes: 0

StriplingWarrior
StriplingWarrior

Reputation: 156624

The key is to recognize that it's not inheriting from (or implementing) a parameterized version of itself, but rather inheriting from (or implementing) another class or interface, and using itself as a generic parameter for that target type.

For example, IComparable<T> says that there will be a CompareTo() method that takes an object of type T as a parameter. So by implementing IComparable<SomeClass> you're simply guaranteeing that a method with that signature will exist on this class:

public class SomeClass : IComparable<SomeClass>
{
    public int CompareTo(SomeClass other)
    {
        //...
    }
}

And yes, this is fairly common practice. Classes often implement the generic IComparable<> and IEquatable<> interfaces to show that they can be compared with other items of the same type. It's maybe also worth mentioning that enums in Java are declared as extending Enum<> of themselves--a pattern which is not common in C#, but does appear from time to time.

Upvotes: 9

sara
sara

Reputation: 3589

It doesn't really have to be convenient to express it in english for it to be valid code, although I'd probably read that as "SomeClass is comparable and equatable to itself". That doesn't really explain what's going on though, it's just a way of expressing it.

In C# types can be generic over categories of other types. Generic types are basically "type constructors". They take other types as parameters, and use them to construct new types. For instance, IEnumerable<int> and IEnumerable<string> are two completely different types. The non-generic version (IEnumerable) is a third one. In C# a type A can inherit ANY other type B as long as none of the following is true (I hope I didn't miss anything):

  • B is already a subtype of A
  • B is a class and A has already inherited another class
  • B is a struct
  • A is an interface but B is not
  • A is the same type as B
  • B is sealed
  • A is a struct and B is not an interface

This even makes the following code legal:

class Foo<T>
{
    public T Value;
}

class Foo : Foo<int>
{
}

Foo and Foo<T> are different types, so there's no problem at all for one to inherit the other.

You can read more about generics here:

https://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx

And about inheritance here:

https://msdn.microsoft.com/en-us/library/ms173149.aspx

Upvotes: 0

gh9
gh9

Reputation: 10703

It is not Inheriting, It is implementing the IComparable Interface. what is going on is

Someclass Implements the Icomparable and the IEquatable interface. Implementing an interface is like signing a contract stating you gaurentee that this class will implement the methods on an interface.

Icomparable msdn, IEquatable. If you look at the MSDN pages you can see that SomeClass gaurentees it will implement the methods in some fashion.

This is very common practice and it is many different names. The ones I hear most are programming by contract and Implementation over Inhertience. It lets you do a lot of cool things, like Dependency Injection, Proper Unit testing, better Generics. It does this because the compiler doesnt need to know the concrete class that your object is implementing. It just needs to know that it has certain functions on it. For further reading on this I would read Chapter one of the gang of four Design pattern book.

Wikipedia link Specifically the Introduction to Chapter one section

Upvotes: 0

Related Questions