C# generic class and EqualityComparer - c#

Could anyone explain me what's wrong in the following class declaration:
private class PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> :
IComparer<PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType>>
where TPriorityValue : IComparable
where IIdentifiableEntry : Identifier<IType>
{
public TPriorityValue Priority{get;private set;}
public IIdentifiableEntry Entry{get;private set;}
public PriorityQueueEntry(TPriorityValue val,IIdentifiableEntry entry)
{
Priority = val;
Entry = entry;
}
public int Compare(PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> first, PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> second)
{
if (first.Priority.CompareTo(second.Priority) < 0)
{
return -1;
}
else if (first.Priority.CompareTo(second.Priority) > 0)
{
return 1;
}
return EqualityComparer<IIdentifiableEntry>.Default.Equals( first.Entry.Id, second.Entry.Id);
}
}
The compiler complaing on the line where I use EqualityComparer. The error is the following:
error CS0176: Static member `object.Equals(object, object)' cannot be
accessed with an instance reference, qualify it with a type name
instead
I can't see where I'm using an instance reference.
Sorry, my fault. I posted an incomplete question.
Just for completeness, Idetifier class is just the following:
public interface Identifier<ID_TYPE>
{
ID_TYPE Id{get;set;}
}
using EqualityComparer there, was due to a copy and paste mistake(sorry guys, too much generic code today).
Of course my question was misposed, because I didn't give you all the elements you needed to answer (I'll remove it soon).
I needed IType to be IConvertible.
Thanks to all anyway.

This is an instance reference:
EqualityComparer<IIdentifiableEntry>.Default
The first problem is that you don't want to call object.Equals(object, object) at all. You really want to be calling the method on the equality comparer - but you're trying to call it with arguments which aren't convertible to IIdentifieableEntry.
The second problem is that you're trying to perform an ordering comparison, not an equality comparison, so you want Comparer<T>, not EqualityComparer<T>.
It's not clear what you're trying to achieve, but this code would at least compile:
return Comparer<IIdentifiableEntry>.Default.Compare(first.Entry, second.Entry);
If you really want to compare the Id properties, you need an equality comparer for the ID property type - and we don't know what that type is.
I suspect it's more likely that you really want something like this:
return Comparer<string>.Default.Compare(first.Entry.Id, second.Entry.Id);
... but it depends on the type of Id.

You have not shown the declaration of Identifier nor EqualityComparer. But I assume you need to change the line to something like:
return EqualityComparer<IIdentifiableEntry>.Default.Equals<IType>( first.Entry.Id, second.Entry.Id);
[EDIT]
As per Jon's comment. You do not want to equality comparer at all. Asumming that that Entry.Id is IComparable, then just:
return first.Entry.Id.CompareTo(second.Entry.Id);
I would recommend that Entry is restricted to IComparable, so we get something like:
class PriorityQueueEntry>
where TPriorityValue : IComparable
where TEntry : IComparable
{
public TPriorityValue Priority{get;private set;}
public TEntry Entry{get;private set;}
public PriorityQueueEntry(TPriorityValue val, TIdentifiableEntry entry)
{
Priority = val;
Entry = entry;
}
public int Compare(PriorityQueueEntry<TPriorityValue, TEntry first, PriorityQueueEntry<TPriorityValue, TEntry> second)
{
if (first.Priority.CompareTo(second.Priority) < 0)
{
return -1;
}
else if (first.Priority.CompareTo(second.Priority) > 0)
{
return 1;
}
return first.Enrtry.CompareTo(second.Entry);
}
}
You may want to add some null checks if TEntry is a class.

Finally I solved this way:
private class PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> :
IComparer<PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType>>
where TPriorityValue : IComparable
where IIdentifiableEntry : Identifier<IType>
where IType : IConvertible
{
public TPriorityValue Priority{get;private set;}
public IIdentifiableEntry Entry{get;private set;}
public PriorityQueueEntry(TPriorityValue val,IIdentifiableEntry entry)
{
Priority = val;
Entry = entry;
}
public int Compare(PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> first, PriorityQueueEntry<TPriorityValue,IIdentifiableEntry,IType> second)
{
if (first.Priority.CompareTo(second.Priority) < 0)
{
return -1;
}
else if (first.Priority.CompareTo(second.Priority) > 0)
{
return 1;
}
return first.Entry.Id.ToUInt32(NumberFormatInfo.CurrentInfo) < first.Entry.Id.ToUInt32(NumberFormatInfo.CurrentInfo) ? -1:1;
}
}

Related

C# - No implicit reference conversion from 'T' to 'System.IComparable<T>'

I have taken the following class from another SO question:
public class Range<T> where T : IComparable<T>
{
public T Minimum { get; set; }
public T Maximum { get; set; }
public override string ToString() { return String.Format("[{0} - {1}]", Minimum, Maximum); }
public Boolean IsValid() { return Minimum.CompareTo(Maximum) <= 0; }
public Boolean ContainsValue(T value)
{
return (Minimum.CompareTo(value) <= 0) && (value.CompareTo(Maximum) <= 0);
}
}
I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
public class Ranges<T> where T : Range<T>
{
private List<Range<T>> rangelist;
public void add(Range<T> range)
{
rangelist.Add(range);
}
public Boolean ContainsValue(T value)
{
foreach (Range<T> range in rangelist)
{
if (range.ContainsValue(value)) return true;
}
return false;
}
}
However, i am getting the error The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Range<T>'. There is no implicit reference conversion from 'T' to 'System.IComparable<T>'.
What exactly is going wrong here?
You don't seem to need the constraint where T : Range<T>
Just repeat the comparable constraint:
public class Ranges<T> where T : IComparable<T>
{
}
If you rewrite your second class slightly, you'll see why:
public class Ranges<U> where U : Range<U>
{
private List<Range<U>> rangelist;
public void add(Range<U> range)
{
rangelist.Add(range);
}
...
}
The error is telling you the compiler does not know if U is convertible to IComparable<U>, which is apparent from the declaration of Ranges<U> and Range<T> (Range<T> does not implement any interfaces).
More importantly, you have a recursing generic argument!
If U is Range<U>, then your class looks like Ranges<Range<T>> where T is U, and so on and so forth.
From what I can tell, you're not looking to write:
Ranges<Range<int>> x = ...;
But rather:
Ranges<int> x = ...;
Which would mean:
public class Ranges<T> where T : IComparable<T>
{
private List<Range<T>> rangelist;
...
You don't need new classes for that, use linq.
list1.All(x=>list2.Any(y=>y == x))
UPDATE: You are saying : I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
So effectively you have list of lists. Or more generally IEnumerable of IEnumerables.
There is enough standard generic data structures to handle this scenario
public static class ListOfListExtention {
public static bool ContainAny( this List<List<int>> lists, int number ) {
return lists.Any(l=>l.Any(x=>x == number))
}
}
Which can be rewritten in more generic way using IComparable interface
public static class ListOfListExtention {
public static bool ContainAny<T>
(this List<List<int>> lists, int value ) where T : IComparable<T> {
return lists.Any(l=>l.Any(x=>x == value))
}
}
So to compare with accepted answer, why wrap List in new class if you can just have one extension method.

'The type arguments cannot be inferred from the usage'

I am having some troubles with generics and inheritance. I have an abstract class called CriteriaBase whose job it is to determine if an entity T matches the criteria defined in any sub-classes. The sub-classes have to implement a method which returns a Func representing the criteria. The problem arises when I try to use generics for the Func. Hopefully some code will illustrate my problem.
public abstract class CriteriaBase<T, U>
where T : ICrossoverable
where U : IChromosome
{
protected abstract Func<U, bool> Criteria { get; }
//some code removed for brevity
private int GetNumberOfCriteriaMatches(T season)
{
//1. works
//Func<IChromosome, bool> predicate = c => c.Genes == null;
//return season.Chromosomes.Count(predicate);
//2. doesn't work - The type arguments for method 'int
//System.Linq.Enumerable.Count<TSource>(this IEnumerable<TSource>,
//Func<TSource, bool>)'
//cannot be inferred from the usage. Try specifying the type arguments
//explicitly.
return season.Chromosomes.Count(Criteria);
}
}
My intention is that the CriteriaBase class should be generic and completely reusable.
An example sub-class:
public class TopTeamsPlayingEachOtherCriteria : CriteriaBase<Season, MatchDay>
{
//some code removed for brevity
protected override Func<MatchDay, bool> Criteria
{
get { return matchDay =>
matchDay.Fixtures.Count(
fixture =>
fixture.HomeTeam.TableGrouping.Ordering == 1
&& fixture.AwayTeam.TableGrouping.Ordering == 1) > 1; }
}
}
The problem is in the GetNumberOfCriteriaMatches() method. Option 2 is how I originally wrote the code but I get the compile error as listed. If I use option 1 then the code compiles but it means that when I override Criteria in the sub-class, I have to use IChromosome instead of MatchDay which doesn't work (I need to access specific features of a MatchDay). In my simple mind, options 1 and 2 are equivalent. Option 2 simply replaces IChromosome with a generic type U which is restricted to a class that implements IChromosome.
Is what I'm trying to achieve possible? If so, what am I missing/misunderstanding? If not, how should I approach this problem?
For completeness (included at the end as I'm not sure how much it helps with the question), here are the two entities that I'm currently using for T (Season) and U (MatchDay).
public class Season : ICrossoverable
{
private readonly IEnumerable<MatchDay> _matchDays;
public Season(IEnumerable<MatchDay> matchDays)
{
_matchDays = matchDays;
}
public IEnumerable<MatchDay> MatchDays
{
get { return _matchDays; }
}
//ICrossoverable implementation
public IEnumerable<IChromosome> Chromosomes
{
get { return _matchDays; }
}
}
public class MatchDay : IChromosome
{
private readonly int _week;
private readonly List<Fixture> _fixtures;
public MatchDay(int week, List<Fixture> fixtures)
{
_week = week;
_fixtures = fixtures;
}
//some code removed for brevity
public IEnumerable<Fixture> Fixtures
{
get { return _fixtures; }
}
//IChromosome implementation
public IEnumerable<IGene> Genes
{
get { return Fixtures; }
}
}
Well this is the problem:
public IEnumerable<IChromosome> Chromosomes
You're only declaring that you're returning a sequence of IChromosome values. Your criterion expects MatchDay values. You happen to know that it's actually returning a sequence of MatchDay values, but the compiler doesn't.
You could use Cast<> to check this at execution time:
return season.Chromosomes.Cast<U>().Count(Criteria);
... or you could change Chromosomes to return an IEnumerable<MatchDay>. Unfortunately we can't really tell whether that's a valid answer or not as we don't know how ICrossoverable is declared. Perhaps you should make ICrossoverable generic in the element type?
You should use keyword in before U in CriteriaBase definition. Something like this:
public abstract class CriteriaBase<T, in U>
where T : ICrossoverable
where U : IChromosome
Update. It will not work.
Try to specify type explicitly
private int GetNumberOfCriteriaMatches(T season)
{
....
return season.Chromosomes.Count<IChromosome>(Criteria);
}

C# How do i access an element of a class when the type of class is Generic? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C# how do I compare two objects if they are of same type?
I have a generic function,
class Something {
public int found;
public Something() {
this.found = true;
}
}
List<Something> something;
public int countFound<T>(List<T> Organisms)
{
if (typeof(T) == typeof(Something))
{
foreach (T organism in Organisms)
{
// here i want to check something like organism.found == true how do i do it?
}
}
return 0;
}
Thanks in advance for all the help!
You probably want something like this:
class Organism
{
public bool Found
{
get;
set;
}
}
class Something : Organism
{
public Something()
{
this.Found = true;
}
}
public class Program
{
public int countFound<T>(List<T> Organisms)
where T : Organism
{
foreach (T organism in Organisms)
{
if (organism.Found)
{
// Do something with the organism
}
}
return 0;
}
}
The key points here are:
You have a common base class called Organism that defines the Found property
The Something class derives from Organism, setting Found to true when it gets constructed
The CountFound method has a generic constraint (the where clause) on T specifying that it must derive from Organism (The Something meets this criteria). This then allows you to use any method or property that Organism provides in the method - in this case Organism.Found.
There are two options here, depending on what you want the function to do:
If the countFound function must take all types T, but you want a special case when T is (or inherits from) Something, then you can use this:
public int countFound<T>(List<T> Organisms)
{
if (typeof(T) == typeof(Something) || typeof(T).IsSubclassOf(typeof(Something)))
{
foreach (T organism in Organisms)
{
Something s = (Something)(object)organism;
// do whatever you like with s
}
}
return 0;
}
If you only want the function to take type T when T is (or inherits from) Something, then that's simpler:
public int countFound<T>(List<T> Organisms) where T : Something
{
foreach (T organism in Organisms)
{
// here organism will have all of the properties of Something
}
return 0;
}
You must limit your generic to one (or more) interface which dictates to implement to properties which are needed by your generic!
Let's say interface IFound implements the property you want to check:
public int countFound<T>(List<T> Organisms) where T : IFound
{
if (typeof(T) == typeof(Something))
{
foreach (T organism in Organisms)
{
if(organism.found)) // done because IFound tells T has a property with this name
}
}
return 0;
}
IFound is an interface you must implement by yourself. For example:
interface IFound
{
bool Found { get; }
}
Your class Something must implement IFound:
class Something : IFound
{
public bool Found
{
get { return true; } // implement your condition in a method called here
}
}
Then you can call your method like you wanted:
int a = countFound<Something>(List<Something> parameter);
In your scenario it seems you wouldn't want to try to implement an equality function because equality would always be defined within the context of the types you are comparing(specific code per type to do the comparisons). This would work for you if all your T 's were of a common type(base class) and the equality condition could be expressed in terms of the base class' common properties etc...

Work on object of type GenericType<T> regardless of T

In case two classes are of the same GenericType<> regardless of T I would like to do some stuff. Is this possible?
// class is given; I can't change it!!
public class MyGeneric<T> : MyBaseClass where T : struct, IComparable, IConvertible
{
public T MyProperty { get; set; }
}
public void DoStuff(MyBaseClass objA, MyBaseClass objB)
{
...
if (objA.GetType().IsGenericType && objA.GetGenericTypeDefinition() == typeof(MyGeneric<>) &&
objA.GetType() == objB.GetType())
{
//here I know that my objects do have a "MyProperty"
//I would like to do something like:
if (((MyGeneric<T>)objA).MyProperty.CompareTo(((MyGeneric<T>)objB).MyProperty) > 0) //doesn't work!!!!
{
//do stuff
}
}
}
It can be made to work if you change the DoStuff method signature to
public void DoStuff<T>(MyBaseClass objA, MyBaseClass objB)
where T : struct, IComparable, IConvertible
{
// ...
}
However, you would have to know the type of T at compile time in order to call the method; I 'm not sure if this would solve your problem.
Apart from that, the other solution is to use reflection:
var valueA = (IComparable)objA.GetType().GetProperty("MyProperty").GetValue(objA, null);
var valueB = (IComparable)objB.GetType().GetProperty("MyProperty").GetValue(objB, null);
if (valueA.CompareTo(valueB) > 0) {
// ...
}
This really doesn't make any sense:
objA.GetType() == objB.GetType() ensures, that they are of the same type, i.e. not independent from T
If point 1 would be solved by simply removing this check, it still would make no sense to compare these properties, because the only thing that is the same in both instances is the name of the property. The type might be different. What should be the result of that?
If you really want to compare the properties, only if T is the same for both instances, just use this method:
public void DoStuff<T>(MyGeneric<T> objA, MyGeneric<T> objB)
where T : struct, IComparable, IConvertible
{
if (objA.MyProperty.CompareTo(objB.MyProperty) > 0)
{
//do stuff
}
}
If you don't know T at compile time, you can use reflection as Jon suggests or you can use the new dynamic keyword if you are using .NET 4:
public void DoStuff(MyBaseClass objA, MyBaseClass objB)
{
if (objA.GetType().IsGenericType &&
objA.GetGenericTypeDefinition() == typeof(MyGeneric<>) &&
objA.GetType() == objB.GetType()
)
{
dynamic objADyn = objA;
dynamic objBDyn = objB;
if (objADyn.MyProperty.CompareTo(objBDyn.MyProperty) > 0)
{
//do stuff
}
}
}

implict type cast in generic method

why do I get a compiler error in the following code stating: Cannot implicty convert type SpecialNode to T even though T must derive from NodeBase as I defined in the where clause and even though SpecialNode actually derived from NodeBase?
public static T GetNode<T>() where T : NodeBase
{
if (typeof(T) == typeof(SpecialNode))
{
return ThisStaticClass.MySpecialNode; // <-- compiler error
}
if (typeof(T) == typeof(OtherSpecialNode))
{
return ThisStaticClass.MyOtherSpecialNode; // <-- compiler error
}
...
return default(T);
}
The compiler doesn't read your if check to realize that in this particular line, T must be SpecialNode.
You need to cast to NodeBase first, like this:
return (T)(NodeBase)MySpecialNode;
You need to casts because (as far as the compiler knows) T might be MyOtherSpecialNode, and you cannot cast a MyOtherSpecialNode to MySpecialNode.
EDIT: You can do it with a single cast like this:
NodeBase retVal;
if (typeof(T) == typeof(SpecialNode))
retVal = MySpecialNode;
else if (typeof(T) == typeof(OtherSpecialNode))
retVal = MyOtherSpecialNode;
return (T)retVal;
You might see that a condition has been logically met, but the compiler does not "remember" this.
public static T GetNode<T>() where T : NodeBase
{
if (typeof(T) == typeof(SpecialNode)) // OK, you now know T is SpecialNode
{
// the compiler still insists on returning a T,
// and will not assume that MySpecialNode is a T
return MySpecialNode;
}
// ...
return default(T);
}
It's true what others have already said: you must cast MySpecialNode: (T)(NodeBase)MySpecialNode (which you can do safely, because you have already checked that T is SpecialNode).
It's easy to think of this as a shortcoming of the compiler; but this is just a mistake stemming from how obvious it seems that MySpecialNode is a T. Suppose I had a method like this:
public T Get<T>() {
if (typeof(T).FullName.Equals("System.Int32"))
return 5;
else
return default(T);
}
Should this compile? I should hope not; the compiler needs to guarantee that it's returning an object of type T, and it can't be sure that 5 will meet that requirement just from some bizarre check that I the developer have performed. (Yes, I know that T is int, but I would not expect any reasonable compiler to determine that from a comparison of the System.Type.FullName property.)
Checking if (typeof(T) == typeof(SpecialNode)) is really not so different from that.
The problem is that the function may be called with a type parameter T, which derives from NodeBase but not from SpecialNode. The compiler doesn't check the semantics of the if statement, so it doesn't know, that T has to be a specialNode.
You would need to use an explicit cast to T in order to satisfy your compiler.
You could also do:
public static T GetNode<T>() where T : NodeBase
{
T result;
result = ThisStaticClass.MySpecialNode as T;
if (result != null) return result;
result = ThisStaticClass.MyOtherSpecialNode as T;
if (result != null) return result;
return default(T);
}
Edit: If the static classes are already null, this probably wouldn't have the intended effect.
Ah, that moment you wish the language had some kinda static polymorphism. Type checking in a generic method is not very cool. This can be a better solution if your requirements let:
public abstract class NodeBase
{
public abstract NodeBase GetNode();
}
public class SpecialNode : NodeBase
{
public override NodeBase GetNode()
{
return ThisStaticClass.MySpecialNode;
}
}
public class OtherSpecialNode : NodeBase
{
public override NodeBase GetNode()
{
return ThisStaticClass.MyOtherSpecialNode;
}
}
//and in your generic method, just:
public static T GetNode<T>() where T : NodeBase, new()
{
return (T)new T().GetNode();
}
This suffer from a disadvantage that you have to expose a parameterless constructor. In case that's undesirable, may be a slightly better approach is to push the generic call one layer backward, and ask your static class itself to do the work for you. Changing static class definition to something like:
public static T GetNode<T>() where T : NodeBase
{
return ThisStaticClass<T>.GetNode();
}
//in which case ThisStaticClass<T> have awareness of
//parameterless new() constructor of T class, which still need not be good enough
You can get it a bit more strongly typed by going one generic level deeper.
public abstract class NodeBase<T> where T : NodeBase<T>
{
public abstract T GetNode();
}
public class SpecialNode : NodeBase<SpecialNode>
{
public override SpecialNode GetNode()
{
return ThisStaticClass.MySpecialNode;
}
}
public class OtherSpecialNode : NodeBase<OtherSpecialNode>
{
public override OtherSpecialNode GetNode()
{
return ThisStaticClass.MyOtherSpecialNode;
}
}
//avoids cast
public static T GetNode<T>() where T : NodeBase<T>, new()
{
return new T().GetNode();
}
Why not just do the following:
return (T)MySpecialNode;
What version of .NET?
See my answer from a previous post
Using Generics to return a literal string or from Dictionary<string, object>
but the answer is
return (T)MySpecialNode
Because even you do the if check the compiler does not so you have to recast to T

Categories