Generic constraints - c#

Which version is better:
using System;
namespace Utils.Extensions
{
public static class EnumerableExtensions
{
public static bool Between<T>(this T item, T min, T max) where T : IComparable<T>
{
return item.CompareTo(min) >= 0 && item.CompareTo(max) <= 0;
}
}
}
or
using System;
namespace Utils.Extensions
{
public static class EnumerableExtensions
{
public static bool Between<T>(this IComparable<T> item, T min, T max)
{
return item.CompareTo(min) >= 0 && item.CompareTo(max) <= 0;
}
}
}
I think both should work, but which one should I use?

Note that using the second version when T is a value-type means that item will be boxed. Casting a value-type to an interface always requires boxing.
I wouldn't worry too much about this for interfaces in general, but it's worth noting that almost every IComparable<T> implementation in the BCL is a value-type. Only you can decide whether the (small) boxing overhead is acceptable.

I think the second one is better. It won't clutter up intelliSense suggestion list for types that are not IComparable. (It won't in any case.)
And what you are looking for is specific to IComparable.
So, it is clear enough to use the second approach if what you are opting for is readability.

There's an obvious difference between the two. The first one is expected to be used on a type that implements IComparable<T>, where the second one is meant to be use on an IComparable<T>.
Given example A:
IComparable<int> x = 14;
bool y = x.Between(12, 23);
Contrast to example B:
int x = 14;
bool y = x.Between(12, 23);
If you attempt to use example A with your first technique (the generic constraint), then you are going to get a compiler error, because the constraint requires a type that implements IComparable<int>, and not an IComparable<int> itself.
Example B will compile using both techniques. I would advise using the second technique so that it works the same in both situations. It appears to be the convention anyway, probably for this reason. But there are other reasons to avoid using the first one anyway. In situations where you might wish to overload a method for particular types, the second method gives you more flexibility.

I would say the first one, because it says something about every T, where the second one only says that item should be IComparable. Indeed it should do the same, but by means of what you want to say, that every T is IComparable. The first one is better.

Related

Generic version vs interface version of a method

What is the difference between these two methods?
first:
public static int Foo<T>(T first, T second) where T:IComparable
{
return first.CompareTo(second)
}
second:
public static int Foo(IComparable first, IComparable second)
{
return first.CompareTo(second);
}
For the first method, the types of the two parameters have to be same, e.g., int and int. The type has to implement the IComparable interface.
For the second method, the two parameters can have different types. Both types must implement the IComparable interface, but do not have to be the same, e.g., int and string.
Note that the IComparable.CompareTo method will likely throw an exception if the types are not the same. So it's better to make sure that the types are actually the same. You can do this by using your first method, or even better by using the generic IComparable<T> interface.
The follow-up question is, of course: What is the difference between these two methods?
first:
public static int Foo<T1, T2>(T1 first, T2 second) where T1 : IComparable<T2>
{
return first.CompareTo(second);
}
second:
public static int Foo<T>(IComparable<T> first, T second)
{
return first.CompareTo(second)
}
Answer: The first method doesn't box the first argument, while the second method does.
From the code fragment provided the difference that can say, that
Generics version:
for generics new code will be generated for every type defined
Foo<Class1>, Foo<Class2>, Foo<Class3>.
you need to define a type at compile time
Interface version:
benefit from OOP concepts, hiding implementation details from the actual code.
runtime type definiton (more flexibility), but less "generic" in terms of pure sence of that word.
In general: interface version is more flexible but less generic (everything, by the way, depends naturally on concrete code implementaiton).

Isn't IValueConverter just an example of "Conversions with helper classes"

A coworker and myself where discussing conversion in .NET he pointed out there are four ways to convert a type, at first I could only come up with two, implicit and explicit then he pointed out user defined conversions and using helper classes so I decided to look it up here http://msdn.microsoft.com/en-us/library/ms173105.aspx while reading that it dawned on me that I do a lot of WPF and often times use the IValueConverter interface.
My Question started as - isn't IValueConverter just an example of a conversion with a helper class (when you implement it of course)? Then I was like well, what is the real difference between user-defined conversions and conversions with a helper class? If you follow the links from the above mentioned MSDN page the documentation is sorda slim. Like this is the example from the conversion operators page.
class SampleClass
{
public static explicit operator SampleClass(int i)
{
SampleClass temp = new SampleClass();
// code to convert from int to SampleClass...
return temp;
}
}
It doesn't really make it so clear. To me it looks like a static class that needs an int in the ctor?
Anyway - Hopefully some C# ninja can illuminate this subject. One final thought is, I generally try and stay away from converting things unless there is a real good reason (i.e. parsing a spreadsheet) in regular everyday code I tend to think of it as a code smell, is that considered best practice?
Thanks
This isn't a full answer to your questions, but that code snippet overrides the "explicit cast" of the class, which isn't really intuitive fromt eh method signature. Basically it would allow you to do:
int one = 1;
SampleClass x = (SampleClass)one;
Common sense says that cast should fail, because and int isn't a SampleClass but the code snippet in your question comes into play, and makes the cast possible.
The other complementing method is:
public static implicit operator SampleClass(int i)
Note the keyword here is implicit instead of explicit, and this version would allow for implicit casting, so this would work:
int one = 1;
SampleClass x = one;
Note that you no longer have to specify the cast.

Using object type as a parameter

I've been wondering about this: would you support using simply an object as a parameter in your method? My reason behind doing this would be overloading. Currently, I'm trying to create a method that caters to many different datatypes: string, decimal, DateTime... the list goes on.
It's getting a bit messy though, so I was thinking of doing the following
public void GenericMethod(object val)
{
if (val is string)
// process as string
else if (val is decimal)
// process as decimal
else if (val is DateTime)
// do something for dt
else
// ...
}
What do you think of such a method? Would it incur unnecessary overhead? (during type checking) Have you implemented it? Tell me...
EDIT: Yeah, and just a sidenote, I'm kinda familiar with overloading. But it gets a little annoying when there are like more than 10 overloads...
Yes, that would work. However there are better ways of doing this.
Your best bet is to use overloads:
public void GenericMethod(string val)
{
// process as string
}
public void GenericMethod(decimal val)
{
// process as decimal
}
etc.
Whenever you use a is keyword in your code that's a huge hint that you're probably forgetting to use some important O.O. principles: overloads, subclasses, or the like.
Overloads aren't actually that annoying to work with, just to write. Remember, you're not coding this for yourself today, you're coding this for yourself three months from now when you have to read the code and figure out why the heck you did it that way, or where in the world that bug comes from.
Yet another reason to avoid the "switch on type" technique is for consistency with the .NET framework (and thus people's expectations). Follow Console.Write and the other wide variety of methods that are overridden within and under a given class.
I've been wondering about this: would you support using simply an object as a parameter in your method?
Very rarely. If there's a fixed set of types which are properly supported - and you'll throw an exception otherwise - then I'd use overloads.
If you can actually accept any type, and you'll handle a not-specially-supported type in some well-known way, then it's okay to accept object. That's what LINQ to XML does all over the place, and the result is a very clean API. I'd do it very carefully though - it's rarely a good idea.
And yes, there'd be an overhead. I wouldn't usually make that the basis of the decision though - the overhead will be small enough to be negligible in most cases. Design your API as cleanly as you can, then work out whether it's going to cause a bottleneck.
Yes, it would incur overhead for both type checking and boxing/unboxing the value type. I would recommend the overloads.
Another possibility, as long as you aren't doing a lot of math with the number, would be to make it a generic method. Arithmetic is rather difficult with generics though, as there are no constraints for value types which enables the use of operators.
No need of those!
Just declare as many methods with same name as you want and take each type as argument in each method.[This is called Overloading. e.g. You may have seen that +1 Overloads beside Methods, which implies that there is 1 more Method with same name but with different argument types]
Say Like this :
void Method(decimal d)
{
//Process Decimal
}
void Method(string s)
{
//Process String
}
By default, It will find its own method according to the Type.
There are cases where your approach makes sense. I've used it before, mostly when I have a bunch of processing that is the same for different data types.
But this is not overloading. Overloading would be to define different signatures for the same method name like this:
public void GenericMethod(string val)
{
// process as string
}
public void GenericMethod(decimal val)
{
// process as decimal
}
public void GenericMethod(DateTime val)
{
// do something for dt
}
// Etc.
And for some cases, this approach makes more sense.
Implementing many overloads one of them takes object is no problem. Take a look at Console.WriteLine overloads for example. http://msdn.microsoft.com/en-us/library/system.console.writeline.aspx However, take care that int for example can conflict with double:
int sum(int i, int j)
{
return i + j;
}
double sum(double i, double j)
{
return i + j;
}
object sum(object i, object j)
{
return i.ToString() + j.ToString();
}
==============================
static void Main()
{
sum(1, 2); // Error: ambigous call between `int` and `double` versions
sum(1.0, 2.0); // calls double version, although 1.0 and 2.0 are objects too
sum("Hello", "World"); // object
}

C# Constructor constratint to types that support comparison operators

How do I create a class to store a range of any type provided that the type allows comparison operators to ensure that that the first value provided to the constructor is less than the second?
public class Range<T> where T : IComparable<T>
{
private readonly T lowerBound;
private readonly T upperBound;
/// <summary>
/// Initializes a new instance of the Range class
/// </summary>
/// <param name="lowerBound">The smaller number in the Range tuplet</param>
/// <param name="upperBound">The larger number in the Range tuplet</param>
public Range(T lowerBound, T upperBound)
{
if (lowerBound > upperBound)
{
throw new ArgumentException("lowerBlound must be less than upper bound", lowerBound.ToString());
}
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
I am getting the error:
Error 1 Operator '>' cannot be applied to operands of type 'T' and 'T' C:\Source\MLR_Rebates\DotNet\Load_MLR_REBATE_IBOR_INFO\Load_MLR_REBATE_IBOR_INFO\Range.cs 27 17 Load_MLR_REBATE_IBOR_INFO
You could use
where T : IComparable<T>
... or you could just use an IComparer<T> in your code, defaulting to Comparer<T>.Default.
This latter approach is useful as it allows ranges to be specified even for types which aren't naturally comparable to each other, but could be compared in a custom, sensible way.
On the other hand, it does mean that you won't catch incomparable types at compile time.
(As an aside, creating a range type introduces a bunch of interesting API decisions around whether you allow reversed ranges, how you step over them, etc. Been there, done that, was never entirely happy with the results...)
You cannot constrain a T to support a given set of operators, but you can constrain to IComparable<T>
where T : IComparable<T>
Which at least allows you to use first.CompareTo(second). Your basic numeric types, plus strings, DateTimes, etc., implement this interface.
To combine two suggestions already given, we combine the ability to create Ranges with a manually defined comparison rule, with an over-ride for those types that implement IComparable<T>, and with compile-time safety on the latter.
We take much the same approach as the static Tuple class' Create method. This can also offer concision in allowing us to rely upon type inference:
public static class Range // just a class to a hold the factory methods
{
public static Range<T> Create<T>(T lower, T upper) where T : IComparable<T>
{
return new Range<T>(lower, upper, Comparer<T>.Default);
}
//We don't need this override, but it adds consistency that we can always
//use Range.Create to create a range we want.
public static Range<T> Create<T>(T lower, T upper, IComparer<T> cmp)
{
return new Range<T>(lower, upper, cmp);
}
}
public class Range<T>
{
private readonly T lowerBound;
private readonly T upperBound;
private readonly IComparer<T> _cmp;
public Range(T lower, T upper, IComparer<T> cmp)
{
if(lower == null)
throw new ArgumentNullException("lower");
if(upper == null)
throw new ArgumentNullException("upper");
if((_cmp = cmp).Compare(lower, upper) > 0)
throw new ArgumentOutOfRangeException("Argument \"lower\" cannot be greater than \"upper\".");
lowerBound = lower;
upperBound = upper;
}
}
Now we can't accidentally construct a Range with the default comparer where it won't work, but can also leave out the comparer and have it compile only if it'll work.
Edit:
There are two main approaches to having items comparable in an order-giving way in .NET and this uses both.
One way is to have a type define its on way of being compared with another object of the same type*. This is done by IComparable<T> (or the non-generic IComparable, but then you have to catch type mis-matches at run-time, so it isn't as useful post .NET1.1).
int for example, implements IComparable<int>, which means we can do 3.CompareTo(5) and receive a negative number indicating that 3 comes before 5 when the two are put into order.
Another way is to have an object that implements IComparer<T> (and likewise a non-generic IComparer that is less useful post .NET1.1). This is used to compare two objects, generally of a different type to the comparer. We explicitly use this either because a type we are interested in doesn't implement IComparable<T> or because we want to override the default sorting order. For example we could create the following class:
public class EvenFirst : IComparer<int>
{
public int Compare(int x, int y)
{
int evenOddCmp = x % 2 - y % 2;
if(evenOddCmp != 0)
return evenOddCmp;
return x.CompareTo(y);
}
}
If we used this to sort a list of integers (list.Sort(new EvenFirst())), it would put all the even numbers first, and all the odd numbers last, but have the even and odd numbers in normal order within their block.
Okay, so now we've got two different ways of comparing instances of a given type, one which is provided by the type itself and which is generally the "most natural", which is great, and one which gives us more flexibility, which is also great. But this means that we will have to write two versions of any piece of code that cares about such comparisons - one that uses IComparable<T>.CompareTo() and one that uses IComparer<T>.Compare().
It gets worse if we care about two types of objects. Then we need 4 different methods!
The solution is provided by Comparer<T>.Default. This static property gives us an implementation of IComparer<T>.Compare() for a given T that calls into IComparable<T>.CompareTo.
So, now we generally only ever write our methods to make use of IComparer<T>.Compare(). Providing a version that uses CompareTo for the most common sort of comparisons is just a matter of an override that uses the default comparer. E.g. instead of:
public void SortStrings(IComparer<string> cmp)//lets caller decide about case-sensitivity etc.
{
//pretty complicated sorting code that uses cmp.Compare(string1, string2)
}
public void SortStrings()
{
//equally complicated sorting code that uses string.CompareTo()
}
We have:
public void SortStrings(IComparer<string> cmp)//lets caller decide about case-sensitivity etc.
{
//pretty complicated sorting code that uses cmp.Compare(string1, string2)
}
public void SortStrings()
{
SortStrings(Comparer<string>.Default);//simple one-line code to re-use all the above.
}
As you can see, we've the best of both worlds here. Someone who just wants the default behaviour calls SortStrings(), someone who wants a more specific comparison rule to be used calls e.g. SortStrings(StringComparer.CurrentCultureIgnoreCase), and the implementation only had to do a tiny bit of work to offer that choice.
This is what is done with the suggestion for Range here. The constructor always takes an IComparer<T> and always uses it's Compare, but there's a factory method that calls it with Comparer<T>.Default to offer the other behaviour.
Note that we don't strictly need this factory method, we can just use an overload on the constructor:
public Range(T lower, T upper)
:this(lower, upper, Comparer<T>.Default)
{
}
The downside though, is that we can't add a where clause to this to restrict it to cases where it'll work. This means that if we called it with types that didn't implement IComparer<T> we'd get an ArgumentException at runtime rather than a compiler error. Which was Jon's point when he said:
On the other hand, it does mean that you won't catch incomparable types at compile time.
The use of the factory method is purely to ensure this wouldn't happen. Personally, I'd probably just go with the constructor override and try to be sure not to call it inappropriately, but I added the bit with the factory method since it does combine two things that had come up on this thread.
*Strictly, there's nothing to stop e.g. A : IComparable<B>, but while this is of little use in the first place, one also doesn't know for most uses whether the code using it will end up calling a.CompareTo(b) or b.CompareTo(a) so it doesn't work unless we do the same on both classes. In sort, if it can't be pushed up to a common base-class it's just going to get messy fast.
You can use IComparable interface which is used widely in the .NET framework.

How do i make sure that a datatype implement an IComparable interface

I need to make sure that a datatype implements the IComparable interface, and I was wondering if there was anyway to make that a requirement when you create the object?
You can perhaps use generic to do this, for example:
public static T Create<T>() where T : IComparable<T>, new() {
return new T();
}
Or if you mean "when you create the type" (in code), then no; you'd just have to remember, perhaps using unit-tests to verify that you've done it.
I recommend using the typed IComparable<T> over IComparable - it makes life a lot easier (and avoids some boxing, but that is less of an issue). Finally, remember that you can use Comparer<T>.Default and Comparer.Default in code if you want to duck-type the comparable bit (like how List<T>.Sort() works).
For a generic class you can do:
public class MyType<T>
where T:IComparable<T>
You also might want to look into Comparer<T>.Default. From what I understand it gets the IComparable<T> first, if it can't find that then it gets the IComparable version, otherwise it throws an exception.
double s = 5;
double t = 10;
int result = Comparer<double>.Default.Compare(s, t);

Categories