So I'm rolling my own max heap and I'm doing something wrong with using a generic class extending an interface. Say I have a class like this:
class SuffixOverlap:IComparable<SuffixOverlap>
{
//other code for the class
public int CompareTo(SuffixOverlap other)
{
return SomeProperty.CompareTo(other.SomeProperty);
}
}
And then I create my heap class:
class LiteHeap<T> where T:IComparable
{
T[] HeapArray;
int HeapSize = 0;
public LiteHeap(List<T> vals)
{
HeapArray = new T[vals.Count()];
foreach(var val in vals)
{
insert(val);
}
}
//the usual max heap methods
}
But when I try to do this:
LiteHeap<SuffixOverlap> olHeap = new LiteHeap<SuffixOverlap>(listOfSuffixOverlaps);
I get the error:
The type SuffixOverlap cannot be used as a type parameter T in the generic type or method LiteHeap<T>. There is no implicit reference conversion from SuffixOverlap to System.IComparable.
How do I create LiteHeap as a class that uses generic class T implementing IComparable so I can write new LiteHeap<SomeClass> and it will work where SomeClass implements IComparable
IComparable and IComparable<T> are different, completely-unrelated interfaces.
You need to change that to where T : IComparable<T>, so that it actually matches your class.
Related
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?
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.
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();
}
}
}
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
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
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:
You achieve this kind of view with the "Locals" window.
I recommend that you read some tutorials on c# inheritance, interfaces and generics
I am implementing a binary tree using the following code:
class Binary<T>:Binary
where T: IComparable
{
But I'm also looking to use class objects in the tree:
Binary Bin = null;
Bin = new Binary<Product>();
This obviously doesnt work because Product is not IComparable. I tried doing this to make it work:
public class Product: IComparable<Product>
{
public int Id = 0;
public int CompareTo(Product p)
{
if (p==null)
{
return 1;
}
if (p!=null)
{
return this.Id.CompareTo(p.Id);
}
return 0;
}
Id is the value of Product intended to be used in all comparisons. But this doesn't work and I dont know what else to do. Is it possible to do what i want? Or is there another way I can use the class Product as an IComparable?
Your class Product implements generic IComparable<T>, where your generic class Binary<T> expects generic type that implements non-generic IComparable.
Update Binary<T> declaration to useIComparable<T> in the constraint:
class Binary<T>:Binary
where T: IComparable<T>
{
I've tried to develop a generic class "MinHeap(T)" implementing IComparable. It works fine when generic is "int" or another class "Code". Going further and using for T a generic class "Node(Code)"
leads to the error mentioned below.
I'm probably too new and not understanding subtle differences between IComparable and IComparable(T). Does someone have an idea ?
Thanks in advance for your help,
LJ
public class MinHeap<T> where T : IComparable
{
...
}
public class Node<T> where T : IComparable
{
T data
...
public int CompareTo(object obj)
{
Node<T> otherNode = obj as Node<T>;
return this.data.CompareTo(otherNode.data);
}
...
}
public class Code : IComparable
{
public int freq;
...
public int CompareTo(object obj)
{
Code otherCode = obj as Code;
return this.freq.CompareTo(otherCode.freq);
}
}
static void Main(string[] args)
{
MinHeap<int> hInt = new MaxHeap<int>(heapSeed); // works fine
MinHeap<Code> hCode = new MinHeap<Code>(codeList); // works fine
...
Node<Code>[] nodeCodeList = new Node<Code>[freqList.Length]; // ok
MinHeap<Node<Code>> h = new MinHeap<Node<Code>>(nodeCodeList); // Error
...
}
Error message:
Error 2 The type 'Algorithms.Node(Algorithms.Code)' cannot be used as type parameter 'T' in the generic type or method 'Algorithms.MinHeap(T)'. There is no implicit reference conversion from 'Algorithms.Node(Algorithms.Code)' to 'System.IComparable'.
The class Node<T> does not implement IComparable. It just haves a constraint for the type of T.
It looks like you've tried to implement the decorator pattern. Implement the interface as well and then map the methods to the decorated object.
You're probably better off defining your generic class so that it doesn't require the type to implement IComparable<T>. That's how the .NET generic classes are implemented. They will use the default comparison for the type, or use the IComparer<T> that you pass in. For example, SortedList has these constructors (among others):
SortedList<TKey, TValue>(); // uses default comparer for TKey
SortedList<TKey, TValue>(IComparer<T> comparer); // uses supplied comparer
It's easy enough to implement:
public class MinHeap<T>
{
private IComparer<T> _comparer;
public MinHeap<T>(IComparer<T> comp)
{
_comparer = comp;
}
public MinHeap<T>()
: this(Comparer<T>.Default)
{
}
}
That way, your clients can use MinHeap<T> to hold instances of classes that do not implement IComparable<T>.
When you do your comparisons, you call _comparer.Compare(item1, item2)
On another note, there's no particular need for your heap to require a node. You can implement a binary heap in an array. See, for example, A Generic BinaryHeap Class.
You should implement IComparable interface within Node class, like this:
public class Node<T>: IComparable<Node<T>> // <- IComparable<Node<T>> implemented
where T: IComparable {
T data;
...
#region IComparable<Node<T>> Members
// interface implementation, not just a method
public int CompareTo(Node<T> other) {
// Let us be accurate with possible nulls:
if (Object.ReferenceEquals(null, other))
return 1; // <- or -1 if you think it's right
else if (Object.ReferenceEquals(data, other.data))
return 0;
else if (Object.ReferenceEquals(null, data))
return -1; // <- or 1 if you think it's right
return data.CompareTo(other.data);
}
#endregion IComparable<Node<T>> Members
}
depending on algorithm of min heap, you may have to implement IComparable> in MinHeap class as well
I have a small class that implements a dictionary that maps from the type of an interface to an implementation of that interface that extends from a base class. Unfortunately the abstract base class does not implement the interfaces, so once in the dictionary, there seems to be no way to associate the two. There is another method in this class that is dependent on storing the objects as BaseClass (in fact, most of my class is dependent on that--the getter into the dictionary is somewhat of a convenience).
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (!(base is T)) // How to get rid of this check?
{
throw new ArgumentException("base does not implement " + typeof(T).Name);
}
this.dictionary.Add(typeof(T), base);
}
public T Get<T>()
{
BaseClass base;
this.dictionary.TryGetValue(typeof(T), out base);
return (T)(object)base; // How to get rid of (object) cast?
}
Are there any clever constraints I can use to remove the (base is T) check, the cast to object, or both?
Here is the class setup, for reference:
class BaseClass { }
interface IThing { }
class MyClass : BaseClass, IThing { }
dict.Add<IThing>(new MyClass());
IThing myClass = dict.Get<IThing>();
The only way to get the compile-time enforcement you're looking for would be if you have compile-type knowledge of the derived type being added.
For example, if you also specify a type parameter for the class being added then you could constrain that the class implement the interface type parameter:
public void Add<TInterface, TClass>(TClass #base)
where TClass : BaseClass, TInterface {
this.dictionary.Add(typeof(TInterface), #base);
}
So you could do this:
MyClass ok = new MyClass();
dict.Add<IThing, MyClass>(ok);
But not this:
class MyClassNotIThing : BaseClass { }
MyClassNotIThing notOk = new MyClassNotIThing();
dict.Add<IThing, MyClassNotIThing>(notOk);
Aside from that, generic constraints don't offer a means by which to constrain that a known type (i.e. BaseClass) inherit from a generic type parameter.
Here is the solution I ended up using. There are a few tricks that can make the Add() safe without the check (see the link in a comment to cokeman19's answer), but I opted not to do that as I find this code a bit cleaner.
interface IThing { }
abstract class BaseClass
{
internal T AsInterface<T> where T : class
{
return this as T;
}
}
class MyClass : BaseClass, IThing { }
class DictionaryClass
{
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (base is T)
{
dictionary.Add(typeof(T), base);
}
}
public T Get<T>() where T : class
{
return dictionary[typeof(T)].AsInterface<T>();
}
}
Note that this solution does allow calls like:
myClass.AsInterface<IThingItDoesntImplement>()
but this returns null and I made the function internal to prevent strange uses anyway.
I'd like to create various sorting classes (QuickSort, MergeSort, BucketSort...etc).
I have a common Interface (ISort).
This interface has a method:
Collection<T> Sort(Collection<T> list);
Now when im trying to use a class it seems like i have to declare like this:
ISort<char> sort = new QuickSort();
The QuickSort implementation looks like this:
public class QuickSort : ISort<char>
{
public Collection<char> Sort(Collection<char> list)
{
// TODO: implement this.
return null;
}
}
This implementation is what i dont like because the T template is a char.
How can i keep this class generic so that i can use this class to sort an int, float, double, char...etc?
Just like this:
public class QuickSort<T> : ISort<T>
{
public Collection<T> Sort(Collection<T> list)
{
// TODO: implement this.
return null;
}
}
with
ISort<char> sort = new QuickSort<char>();
Sorting has nothing to do with the data type in the collection being sorted so you shouldn't force a type parameter at the class level. Also you will need to compare objects so they should implement IComparable.
You could design the interface like this and avoid tying the instance of the sorting class to the type it will sort:
interface ISort
{
ICollection<T> Sort<T>(ICollection<T> collection) where T : IComparable<T>;
}
class QuickSort : ISort
{
public ICollection<T> Sort<T>(ICollection<T> collection) where T : IComparable<T>
{
Comparer<T> comparer = Comparer<T>.Default;
// TODO: Implement
return collection;
}
}
Then you can use the same sorting object for all data types. The one drawback to this design, is that you won't be able to store state that is specific based on the generic type parameter. So QuickSort couldn't contain fields that use the generic type paremeter T.