I'm writing a small class which I'm gonna move around when needed like a dll, and it's gonna have different sorting algorithms in it. I want the functions to work with any lists, of any types, including objects. So it's basically like this:
class TemplateSortings<T>
{
List<T> GNRList;
static void SortBubble<T>()
{
//Do stuff with GNRList, which can be a list of any values (nums, strings, objects)
}
}
Now the question I'm having troubles with is this - what is the best way to compare two generic values: overloading comparison operators or having the class inherit IComparable interface? What is better and why?
If you want it to work with any type, you probably shouldn't constrain T to types that implement IComparable, because not all types do.
A simple way to work around this is to let the caller decide how to compare the objects. You just need an extra parameter:
static void SortBubble(Func<T, T, int> comparator)
{
...
}
You can call comparator with 2 arguments and it will give you a negative value, 0, or a positive value indicating that the first parameter is less than, equal to, or greater than the second parameter.
As an example, you can call SortBubble with ints like this:
var sorting = new TemplateSortings<int>();
// populate the list...
sorting.SortBubble((x, y) => x.CompareTo(y)) // pass a lambda
EDIT:
If you don't want an extra parameter and want to check the type inside the method, you can do something like this:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T))) {
// do your sorting
// you need to cast values of type "T" to "Comparable<T>" like this
// var castedValue = (IComparable<T>)tValue;
} else {
throw ...
}
You could generalize your code so it can work with any potentially valid type T:
public static IEnumerable<T> BubbleSort(
this IEnumerable<T> source,
IComparer<T> comparer == null)
{
var currentComparer = comparer ?? Comparer<T>.Default;
//bubble sort with currentComparator
}
Now, you can sort any T whatsoever, if:
T implements IComparable<T>
T implements legacy IComparable
You hand down a Comparator that knows how to compare Ts
It will fail on any other scenario the moment you attempt to perform the first comparison.
I prefer to use IEnumerable<object>, for LINQ extension methods are defined on it, not IEnumerable, so that I can use, for example, range.Skip(2). However, I also prefer to use IEnumerable, for T[] is implicitly convertible to IEnumerable whether T is a reference type or value type. For the latter case, no boxing is involved, which is good. As a result, I can do IEnumerable range = new[] { 1, 2, 3 }. It seems impossible to combine the best of both worlds. Anyway, I chose to settle down to IEnumerable and do some kind of cast when I need to apply LINQ methods.
From this SO thread, I come to know that range.Cast<object>() is able to do the job. But it incurs performance overhead which is unnecessary in my opinion. I tried to perform a direct compile-time cast like (IEnumerable<object>)range. According to my tests, it works for reference element type but not for value type. Any ideas?
FYI, the question stems from this GitHub issue. And the test code I used is as follows:
static void Main(string[] args)
{
// IEnumerable range = new[] { 1, 2, 3 }; // won't work
IEnumerable range = new[] { "a", "b", "c" };
var range2 = (IEnumerable<object>)range;
foreach (var item in range2)
{
Console.WriteLine(item);
}
}
According to my tests, it works for reference element type but not for
value type.
Correct. This is because IEnumerable<out T> is co-variant, and co-variance/contra-variance is not supported for value types.
I come to know that range.Cast() is able to do the job. But it
incurs performance overhead which is unnecessary in my opinion.
IMO the performance cost(brought by boxing) is unavoidable if you want a collection of objects with a collection of value-types given. Using the non-generic IEnumerable won't avoid boxing because IEnumerable.GetEnumerator provides a IEnumerator whose .Current property returns an object. I'd prefer always use IEnumerable<T> instead of IEnumerable. So just use the .Cast method and forget the boxing.
After decompiling that extension, the source showed this:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
if (enumerable != null)
return enumerable;
if (source == null)
throw Error.ArgumentNull("source");
return Enumerable.CastIterator<TResult>(source);
}
private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
foreach (TResult result in source)
yield return result;
}
This basically does nothing else than IEnumerable<object> in first place.
You stated:
According to my tests, it works for reference element type but not for
value type.
How did you test that?
Despite I really do not like this approach, I know it is possible to provide a toolset similar to LINQ-to-Objects that is callable directly on an IEnumerable interface, without forcing a cast to IEnumerable<object> (bad: possible boxing!) and without casting to IEnumerable<TFoo> (even worse: we'd need to know and write TFoo!).
However, it is:
not free for runtime: it may be heavy, I didn't run perfomance test
not free for developer: you actually need to write all those LINQ-like extension methods for IEnumerable (or find a lib that does it)
not simple: you need to inspect the incoming type carefully and need to be careful with many possible options
is not an oracle: given a collection that implements IEnumerable but does not implement IEnumerable<T> it only can throw error or silently cast it to IEnumerable<object>
will not always work: given a collection that implements both IEnumerable<int> and IEnumerable<string> it simply cannot know what to do; even giving up and casting to IEnumerable<object> doesn't sound right here
Here's an example for .Net4+:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
public static void Main()
{
Console.WriteLine("List<int>");
new List<int> { 1, 2, 3 }
.DoSomething()
.DoSomething();
Console.WriteLine("List<string>");
new List<string> { "a", "b", "c" }
.DoSomething()
.DoSomething();
Console.WriteLine("int[]");
new int[] { 1, 2, 3 }
.DoSomething()
.DoSomething();
Console.WriteLine("string[]");
new string[] { "a", "b", "c" }
.DoSomething()
.DoSomething();
Console.WriteLine("nongeneric collection with ints");
var stack = new System.Collections.Stack();
stack.Push(1);
stack.Push(2);
stack.Push(3);
stack
.DoSomething()
.DoSomething();
Console.WriteLine("nongeneric collection with mixed items");
new System.Collections.ArrayList { 1, "a", null }
.DoSomething()
.DoSomething();
Console.WriteLine("nongeneric collection with .. bits");
new System.Collections.BitArray(0x6D)
.DoSomething()
.DoSomething();
}
}
public static class MyGenericUtils
{
public static System.Collections.IEnumerable DoSomething(this System.Collections.IEnumerable items)
{
// check the REAL type of incoming collection
// if it implements IEnumerable<T>, we're lucky!
// we can unwrap it
// ...usually. How to unwrap it if it implements it multiple times?!
var ietype = items.GetType().FindInterfaces((t, args) =>
t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>),
null).SingleOrDefault();
if (ietype != null)
{
return
doSomething_X(
doSomething_X((dynamic)items)
);
// .doSomething_X() - and since the compile-time type is 'dynamic' I cannot chain
// .doSomething_X() - it in normal way (despite the fact it would actually compile well)
// `dynamic` doesn't resolve extension methods!
// it would look for doSomething_X inside the returned object
// ..but that's just INTERNAL implementation. For the user
// on the outside it's chainable
}
else
// uh-oh. no what? it can be array, it can be a non-generic collection
// like System.Collections.Hashtable .. but..
// from the type-definition point of view it means it holds any
// OBJECTs inside, even mixed types, and it exposes them as IEnumerable
// which returns them as OBJECTs, so..
return items.Cast<object>()
.doSomething_X()
.doSomething_X();
}
private static IEnumerable<T> doSomething_X<T>(this IEnumerable<T> valitems)
{
// do-whatever,let's just see it being called
Console.WriteLine("I got <{1}>: {0}", valitems.Count(), typeof(T));
return valitems;
}
}
Yes, that's silly. I chained them four (2outsidex2inside) times just to show that the type information is not lost in subsequent calls. The point was to show that the 'entry point' takes a nongeneric IEnumerable and that <T> is resolved wherever it can be. You can easily adapt the code to make it a normal LINQ-to-Objects .Count() method. Similarly, one can write all other operations, too.
This example uses dynamic to let the platform resolve the most-narrow T for IEnumerable, if possible (which we need to ensure first). Without dynamic (i.e. .Net2.0) we'd need to invoke the dosomething_X through reflection, or implement it twice as dosomething_refs<T>():where T:class+dosomething_vals<T>():where T:struct and do some magic to call it properly without actually casting (probably reflection, again).
Nevertheless, it seems that you can get something-like-linq working "directly" on things hidden behind nongeneric IEnumerable. All thanks to the fact that the objects hiding behind IEnumerable still have their own full type information (yeah, that assumption may fail with COM or Remoting). However.. I think settling for IEnumerable<T> is a better option. Let's leave plain old IEnumerable to special cases where there is really no other option.
..oh.. and I actually didn't investigate if the code above is correct, fast, safe, resource-conserving, lazy-evaluating, etc.
IEnumerable<T> is a generic interface. As long as you're only dealing with generics and types known at compile-time, there's no point in using IEnumerable<object> - either use IEnumerable<int> or IEnumerable<T>, depending entirely on whether you're writing a generic method, or one where the correct type is already known. Don't try to find an IEnumerable to fit them all - use the correct one in the first place - it's very rare for that not to be possible, and most of the time, it's simply a result of bad object design.
The reason IEnumerable<int> cannot be cast to IEnumerable<object> may be somewhat surprising, but it's actually very simple - value types aren't polymorphic, so they don't support co-variance. Do not be mistaken - IEnumerable<string> doesn't implement IEnumerable<object> - the only reason you can cast IEnumerable<string> to IEnumerable<object> is that IEnumerable<T> is co-variant.
It's just a funny case of "surprising, yet obvious". It's surprising, since int derives from object, right? And yet, it's obvious, because int doesn't really derive from object, even though it can be cast to an object through a process called boxing, which creates a "real object-derived int".
I am confused about how LINQ sum method works.
So, we have for example an int array and int structure doesn't have a sum method.
But then when we include LINQ, magically it does.
How is the sum method added to the structure so we can invoke arr.sum() ? Through some kind of inheritance or how?
How is the sum method added to the structure
Most collection classes implement IEnumerable<T>. Sum, as in your example, is an extension method for IEnumerable<T>.
Extension methods are essentially static classes with static methods, where each methods first value is added the this keyword. This way, the compiler recognizes it as an extension method to be applied to the type.
Here is Enumerable.Sum in it's simplest form declared on IEnumerable<decimal>:
public static decimal Sum(this IEnumerable<decimal> source)
{
if (source == null) throw Error.ArgumentNull("source");
decimal sum = 0;
foreach (decimal v in source) sum += v;
return sum;
}
There are many overloads of Sum, each with a different type of an integral and floating point type. They can be found here if you're interested.
All extension methods are applied on the given type. Given that an array implements IEnumerable<T>, it also gets these methods as an add on.
I have a question about reversing the elements of a list in C#.
The ultimate goal is to get the last N elements of a list.
Suppose I have a list of decimals.
List<decimal> listOfDecimals = new List<decimal>() { 1.5m, 2.4m, 3.6m, 0.1m };
This is my attempt to get a list containing the last 2 elements of listOfDecimals.
List<decimal> listOfLastTwoElements = listOfDecimals.Reverse<decimal>().Take<decimal>(2).Reverse<decimal>().ToList<decimal>();
My question is, if I replaced Reverse<>() with Reverse(), there is a syntax error as flagged by VS.
Can anyone please let me know when I should use Reverse(), and when to use Reverse<>()?
This is because List itself has a Reverse method. This reverse method does not return anything.
The reverse method on List<T> takes precedence over the extension method on IEnumerable<T>.
Confusing is that when you just have an IEnumerable<T>, you can use Reverse() without type argument. Then the type inference of the compiler resolves the generic type argument. So the extension method looks the same as the method on List<T>.
var reversed1 = Enumerable.Empty<int>().Reverse(); // works
var reversed2 = Enumerable.Empty<int>().Reverse<int>(); // works and is the same as the line above.
var reversed3 = new List<int>().Reverse(); // does not work
var reversed4 = new List<int>().Reverse<int>(); // works
Reverse() is a method of List<T>, Reverse<T>() is a (extension)method of IEnumerable<T>, so that includes List<T>.
If you want to take the last 2 elements of an IEnumerable, you can just do Last(2). This will return an IEnumerable<T>, so if you want that in a List, you must call ToList on that.
List<T> also has a method `RemoveRange()`, so if you want to remove all but the last 2 elements:
listOfDecimals.RemoveRange(0, listOfDecimals.Count - 2)
I have 3 "Lists" all of different types and at the moment I have to pass them to 3 different functions to go output their contents because I don't know how to convert them to one type.
IEnumerable<IGrouping<string, DynamicNode>>
IOrderedEnumerable<DynamicNode>
IEnumerable<DynamicNode>
How can I create a function to accept all 3 types so I can loop through them there without creating 3 different functions and duplicating code?
public void constructHtml(???? nodeList){
foreach(dynamic child in nodeList){
//etc..
}
}
You could always create a generic method and check the type in the method. Something like
public void constructHtml<T>(T nodeList){
// Check type T and do something with it
}