Convert and Object Class to IComparable in c# - c#

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>
{

Related

Generic method with type constraints or base class parameter

If I write a method accepting a parameter which derives from a BaseClass (or an interface), as far as I know there are two ways to achieve that:
void MyMethod<T>(T obj) where T : BaseClass { ... }
and
void MyMethod(BaseClass obj) { ... }
What are the differences between the two methods?
In this example there isn't a big difference between the two, you can access the same members inside the method and you can call it with the same derived classes. There is a runtime difference as a generic method is compiled for each type it is invoked with.
Where generics come in useful would be if you would return a value depending on T
With generics you could do the following
T MyMethod<T>(T obj) where T : BaseClass { ... }
MyMethod(derivedInstance).derivedProperty
Without this would be an error:
BaseClass MyMethod(BaseClass obj) { ... }
MyMethod(derivedInstance).derivedProperty // error
Note Although you mention constraining to a base class, it is worth mentioning that if you constrain not to a class, but to an interface, extra boxing will occur if the implementation is by a struct in the non generic version, this can have severe performance implications.
When T is constrained to a base class, there is not really much difference apart from what has already been stated.
When T is constrained to an interface, the difference can be huge:
int FrobNonGeneric(IFrobbable frob) { //... }
int Frob<T>(T frob) where T: IFrobbable { //... }
struct Frob: IFrobbable { ... }
FrobNonGeneric(new Frob()); //boxing!
Frob(new Frob()); //no boxing
Definitely the example you quoted does not make much difference other than run time execution performance as mentioned in other answers.
Leaving aside generic collections benefits (performance improvement by avoiding boxing/unboxing for example) which we all aware of and we use frequently - Generics also works great from a consumer perspective. For example, the below code snippet is self explanatory to visualize API usage flexibility from a consumer perspective :
interface IEntity
{
int Id {get;set;}
}
class Student : IEntity
{
int Id {get;set;}
string SubjectOpted {get;set;}
}
class Employee : IEntity
{
int Id {get;set;}
string DepartmentName{get;set;}
}
interface INonGenericRepository
{
IEntity Get(int id)
}
interface IGenericRepository<T> where T:Entity
{
T Get(int id)
}
class NonGenericRepository : IRepository
{
public IEntity Get(int id) {/*implementation goes here */
}
class GenericRepository<T> : IRepository<T>
{
public T Get(int id) {/*implementation goes here */
}
Class NonGenericStudentConsumer
{
IEntity student = new NonGenericFRepository().Get(5);
var Id = student.Id
var subject = student.SubjectOpted /*does not work, you need to cast */
}
Class GenericStudentConsumer
{
var student = new GenericFRepository<Student>().Get(5);
var Id = student.Id
var subject = student.SubjectOpted /*works perfect and clean */
}
A couple of other use cases promoting flexibility while using generics along with constraints are :
Lets say I want to ensure parameter passed to method implements IAdd and IMultiply and I have class which implements both IAdd,IMulitply like :
public class BusinessOpeartion<T> where T : IAdd, IMultiply{
void SomeBusinessOpeartion(T obj) { /*implementation */}
}
If I need to go via non generic approach, I am forced to create redundant dummy interface like :
interface IDummy : IAdd, IMultiply
public class BusinessOpeartion{
void SomeBusinessOpeartion(IDummy obj) { /*implementation */}
}
Isn't the former approach cleaner?
Also one more small thing just popped up while typing answer. In case you need to, how would you get new instance for parameter type inside method:
you cannot do
IDummy dummy = new IDummy(); /*illegal*/
But with generic you could have; T temp = new T(); provided there is constraint of new()
Also what if you need a default value for parameter type?
you cannot do
var default = default(IDummy); /*illegal*/
But with generic you could have; var default = default(T)
As was said, it matters only once you get a return value. Consider these cases:
BaseClass MyMethod(BaseClass)
DervivedClass temp = new DervivedClass();
//Error. My Method always returns a BaseClass. No implicit casting available
temp = MyMethod(temp);
Compare it to this:
T MyMethod<T>(T) where T : BaseClass
DervivedClass temp = new DerivedClass();
temp = MyMethod<DerivedClass>(temp);
Strong Typification is one of the best friends you have in .NET. Embrace it. Never try to avoid it. The opposite would be cases like we have in PHP and JavaScript: http://www.sandraandwoo.com/2015/12/24/0747-melodys-guide-to-programming-languages/
In the examples included in your question, there isn't much difference between the generic and the non-generic version. But here are some other examples of method signatures that can't be expressed without generics:
T MyMethod<T>(T obj) where T : BaseClass { ... }
void MyMethod<T>(T obj1, T obj2) where T : BaseClass { ... }
void MyMethod<T>(T obj, List<T> list) where T : BaseClass { ... }

Class using generics extending interfaces

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.

C# Generics : CS0311 when implementing generic class that meets a generic interface contract

I have searched around and found one somewhat relevant answer but, for the life of me, I still cannot figure out where I'm going wrong! I am trying to implement some generically typed tree data structures, using code similar to that below, but I get compiler error CS0311.
error CS0311: The type 'Test.TestType' cannot be used as type parameter 'K' in the generic type or method 'Test.TreeIndex<K>'. There is no implicit reference conversion from 'Test.TestType' to 'Test.IIndexable<Test.TestType>'.
I just can't figure out why the compiler doesn't know how to deal with this so any clues would be much appreciated.
public interface IIndexable<K> where K : IComparable
{
byte[] ToBytes();
K FromBytes(byte[] bytes);
}
public class TestType : IIndexable<byte>, IComparable
{
public int CompareTo(object b)
{
return 1;
}
public byte[] ToBytes()
{
return new byte[1];
}
public byte FromBytes(byte[] bytes)
{
return 0;
}
}
public class TreeIndex<K> where K : IComparable, IIndexable<K>
{
public int SomeMethod(K a, K b)
{
return a.CompareTo(b);
}
}
class Program
{
static void Main()
{
TreeIndex<TestType> treeIndex = new TreeIndex<TestType>(); // CS0311 generated twice here
}
}
Your TreeIndex<K> class requires K implement IIndexable<K>, so TestType should implement IIndexable<TestType> instead of IIndexable<byte>
public class TestType : IIndexable<TestType>, IComparable
{
public int CompareTo(object b)
{
return 1;
}
public byte[] ToBytes()
{
return new byte[1];
}
public TestType FromBytes(byte[] bytes)
{
//...
}
}
You might also want to consider using the generic IComparable<T> constraint on your IIndexable<K> interface i.e.
public interface IIndexable<K> where K : IComparable<K>
{
byte[] ToBytes();
K FromBytes(byte[] bytes);
}
Since you have the following generic constraint
public class TreeIndex<K> where K : IComparable, IIndexable<K>
And you´re declaring
TreeIndex<TestType>
You're saying that TestType implements IIndexable<TestType>, which cannot be true.
From Compiler Error CS0311
When a constraint is applied to a generic type parameter, an implicit
identity or reference conversion must exist from the concrete argument
to the type of the constraint. To correct this error
Change the argument you are using to create the class.
Change the argument you are using to create the class.
If you own the class, you can remove the constraint or else do something to enable an implicit reference or identity conversion. For
example, you can make the second type inherit from the first
Based on that, TreeIndex<K> class have to implement IIndexable<TestType> not IIndexable<byte>.
When you write TreeIndex<TestType> compiler asks for IIndexable<K> which means IIndexable<TestType> on your case.
But your TestType class doesn't implement IIndexable<TestType>. It implements IIndexable<byte>.
You are telling the compiler to make a new TreeIndex<TestType>()
The definition for TreeIndex is TreeIndex<K> where K : IComparable, IIndexable<K> which means that the type you pass for the generic must be of IIndexable<K>.
So when you say: TreeIndex<TestType> then the compiler expects TestType to be of type IIndexable<K>, where K is TestType, so it expects TestType to implement IIndexable<TestType>, which it does not. It implements IIndexable<byte> instead.
It is hard to tell what the best solution would be for your case, but one way to solve it is to specify 2 generics:
// change the TreeIndex definition to take 2 generic types
public class TreeIndex<K, Y>
where K : IComparable, IIndexable<Y>
where Y : IComparable
...
// specify both generic types
TreeIndex<TestType, byte> treeIndex = new TreeIndex<TestType, byte>();

Generics and IComparable - error CS00301

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

Casting generic collection to concrete implementation in C# 2.0

Chosen Solution
Thanks for the help everyone. I've decided to do the following.
public static class PersonCollection
{
public static List<string> GetNames(RecordCollection<Person> list)
{
List<string> nameList = new List<string>(list.Count);
foreach (Person p in list)
{
nameList.Add(p.Name);
}
return nameList;
}
}
I'm trying to cast a generic collection RecordCollection to a derived collection PersonCollection, but I get a cast exception:
RecordCollection<Person> col = this.GetRecords<Person>(this.cbPeople);
PersonCollection people = (PersonCollection)col;
The reason I'm trying to do this is two-fold:
The derived classes (eg, PersonCollection) can have instance methods (eg, GetLastNames) which shouldn't be in the base class.
The method GetRecords is generic so I can get a collection of any Record objects.
What is the best approach to solve this in C# 2.0? What is the most elegant approach to solving this?
This is signature of GetRecords:
public RecordCollection<T> GetRecords<T>(ComboBox cb) where T : Record, new()
This is my base implementation:
public abstract class Record : IComparable
{
public abstract int CompareTo(object other);
}
public class RecordCollection<T> : ICollection<T> where T : Record, new()
{
private readonly List<T> list;
public RecordCollection()
{
this.list = new List<T>();
}
// Remaining ICollection interface here
}
I have derived objects based on that base implementation as follows:
public class Person : Record
{
public Person()
{
// This is intentionally empty
}
public string Name
{
get;
set;
}
public override int CompareTo(object other)
{
Person real = other as Person;
return this.Name.CompareTo(real.Name);
}
}
public class PersonCollection : RecordCollection<Person>
{
}
Your approach does not work because cast does not convert instances of one class to instances of another class.
You did not give the code of GetRecords<> method, but presumably GetRecords returns RecordCollection, and not PersonCollection (it has new RecordCollection somewhere in the code, doesn't it?).
You cannot cast RecordCollection to PersonCollection unless this particular instance actually is PersonCollection. Presicely because it does not have these additional methods.
This is like
SomeClass obj=new SomeClass();
DerivedClass o=(DerivedClass)obj; //throws exception
Your best bet is to use some sort of factory call inside GetRecords, so that when you request a 'collection' of Person it will return PersonCollection as RecordCollection<Person>.
A naive implementation can use a few if's, else you can associate concrete collection type to record types via a Dictionary<Type,Type>.
One option:
Make the methods on the derived types non-extension static methods that take in a specialized RecordsCollection ie
public static List<string>GetLastNames( RecordsCollection<Person> people )
so you can have usage along the lines of
RecordCollection<Person> somePeople = GetRecords<Person>(cbPeople);
List<string> lastNames = PersonCollecion.GetLastNames( somePeople );
It's not as pretty as the extension methods, but not too bad either.
edit: Removed erroneous info previously posted and replaced with potential solution

Categories

Resources