What is the difference between this:
void MyMethod(IMyInterface value)
{
//...
}
and this:
void MyMethod<T>(T value) where T : IMyInterface
{
//...
}
The main functional difference is that you can know the actual type of the object inside of the generic method. The T parameter will contain the actual type which can advantageous in certain scenarios.
In the non-generic case you cannot guarantee access to the underlying type of the object. Most of the type you could grab value.GetType() but the user could pass Null and thwart you.
Jared has mentioned some of the points; another interesting one: with generics, you can avoid boxing of value-types as long as you basically don't touch it... so I could have a struct Foo : IMyInterface and pass it in, and it won't get boxed.
The difference gets more noticeable with things like collections:
static void Foo(IEnumerable<IMyInterface> data) {}
vs
static void Foo<T>(IEnumerable<T> data)
where T : IMyInterface {}
Now, since C# 3.0 doesn't have covariance (except for arrays), I can't pass a List<Bar> to the top one, even if Bar : IMyInterface - but I can with the second (implicit T = Bar).
The generic version will require .NET 2.0.
But seriously, while they look similar, there are fundamental differences between them. One difference is, at runtime, the JIT compiler will generate code for each value type that will be used for the generic version. The non-generic version will require the value types to be boxed in order to be passed to the function.
The difference will also matter when dealing with delegates. The signature of MyMethod<int> matches void MyDelegate(int x) while the non-generic version is not matched.
Another difference, using the generic method allows you to specify multiple interfaces that your object must implement:
class Dictionary<TKey,TVal>
where TKey: IComparable, IEnumerable
where TVal: IValue
{ ... }
Another subtle difference is that you can't overload a method only on constraints (constraints aren't part of the signature of the method):
This is illegal:
void MyMethod<T>(T value) where T : IMyInterface
{
//...
}
void MyMethod<T>(T value) where T : IMyInterface2
{
//...
}
while this is legal:
void MyMethod(IMyInterface value)
{
//...
}
void MyMethod(IMyInterface2 value)
{
//...
}
Another caveat to consider with this scenario is the fact that using "where T : <%your base interface or abstraction%>" can be overused in generics rendering your generic type non-generic in nature.
IE: Remember that by isolating your generic method to IMyInterface, you're isolating that method to only those types implementing IMyInterface. So if you've merely chosen to use IMyInterface based on good OOP principles, but you have only one (or in some cases a very small number of) potential type anywhere that'll be implementing that interface, then you've defeated the purpose of using generics. Under that circumstance, the first option would be better.
Only use "where" on your generic type when you're going to have a broader range of types that actually implement IMyInterface.
Yet another difference for generic methods in general (though not for your example) is that if one has a method like T MungeThing<T>(T it) where T:IMungeable<T> and class Fnord implements IMungeable<Fnord>, then code will be able to say: Fnord thing1, thing2; ... thing1 = MungeThing(thing2); and the compiler will know that MungeThing will return a Fnord rather than some arbitrary implementation of IMungable.
Related
There probably are threads here that explain it, but my google fu seems not to be good enough to find them.
I have a pretty common problem: I want to have a non-generic interface that I can put in some kind of enumerable, but ONE of the interface's methods will have a generic input parameter, but as an input parameter, its type is inferable.
For various reasons, I want my implementation to be generic, because the input parameter mentioned above is being used in a few more places in the implementation, among others as type of a property.
Let me give you an example of how it might be implemented to make clearer what I mean:
public interface IThreshold
{
/* various (non-generic) methods and properties */
bool ThresholdExceeded<T>(T value) where T : IComparable<T>, IEquatable<T>;
}
public class Threshold<T> : IThreshold where T : IComparable<T>, IEquatable<T>
{
/* various (non-generic) methods and properties */
T ThresholdValue { get; }
bool IThreshold.ThresholdExceeded<U>(U value) where U : IComparable<U>, IEquatable<U> => ThresholdExceeded((T)(object)value);
public bool ThresholdExceeded(T value)
{
// ...
}
}
[…]
((IThreshold)thresholdOfIntInstance).ThresholdExceeded(5) ? DoSomething();
This will work (unless I introduced an error when simplifying it for the example), however, type safety is of course out the window with the (T)(object)value cast.
Of course I'd rather have a compile time type check than a possible runtime InvalidCastException.
But at the same time, I can't simply use my implementation's T as the ThresholdExceeded input type, since
if I leave out the IThreshold.ThresholdExceeded<U>, it will not recogise ThresholdExceeded(T value) as the implementation of the interface method (of course, the T isn't the same to the compiler)
if I change the constraints for IThreshold.ThresholdExceeded<U> to where U : IComparable<U>, IEquatable<U>, T or something similar, the compiler complains that the constraints in the implementation don't match the interface anymore (I wonder why, since they're only stricter, but ah well)
Is there a pattern that allows me to implement this in a way to keep both compile time type checking AND the comfort of calling the interface method with any kind of type without casting to a specific implementation first (and, of course, while keeping the interface itself non-generic, so that I can have multiple generic instances in an IEnumerable and call the method on them without casting them first)?
UPDATE: As of C# 7.3, this should no longer be an issue. From the release notes:
When a method group contains some generic methods whose type arguments do not satisfy their constraints, these members are removed from the candidate set.
Pre C# 7.3:
So I read Eric Lippert's 'Constraints are not part of the signature', and now I understand that the spec specifies that type constraints are checked AFTER overload resolution, but I'm still not clear on why this MUST be the case. Below is Eric's example:
static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main()
{
Foo(new Giraffe());
}
This doesn't compile because overload resolution for: Foo(new Giraffe()) infers that Foo<Giraffe> is the best overload match but then the type constraints fail and a compile-time error is thrown. In Eric's words:
The principle here is overload resolution (and method type inference) find the best possible match between a list of arguments and each candidate method’s list of formal parameters. That is, they look at the signature of the candidate method.
Type constraints are NOT part of the signature, but why can't they be? What are some scenarios where it is a bad idea to consider type constraints part of the signature? Is it just difficult or impossible to implement? I'm not advocating that if the best chosen overload is for whatever reason impossible to call then silently fallback to the second best; I would hate that. I'm just trying to understand why type constraints can't be used to influence the choosing of the best overload.
I'm imagining that internally in the C# compiler, for overload resolution purposes only (it doesn't permanently rewrite the method), the following:
static void Foo<T>(T t) where T : Reptile { }
gets transformed to:
static void Foo(Reptile t) { }
Why can't you sort of "pull in" the type constraints into the formal parameter list? How does this change the signature in any bad way? I feel like it only strengthens the signature. Then Foo<Reptile> will never be considered as an overload candidate.
Edit 2: No wonder my question was so confusing. I didn't properly read Eric's blog and I quoted the wrong example. I've edited in the example I think more appropriate. I've also changed the title to be more specific. This question doesn't seem as simple as I first imagined, perhaps I'm missing some important concept. I'm less sure that this is stackoverflow material, it may be best for this question/discussion to be moved elsewhere.
The C# compiler has to not consider type constraints as part as the method signature because they are not part of the method signature for the CLR. It would be disastrous if the overload resolution worked differently for different languages (mainly due to the dynamic binding that may happen at runtime and should not be different from one language to another, or else all hells would break loose).
Why was it decided that these constraints would not be part of the method signature for the CLR is another question alltogether, and I could only make ill informed suppositions about that. I'll let the people in the know answer that.
If T matches multiple constraints, you create an ambiguity that cannot be automatically resolved. For example you have one generic class with the constraint
where T : IFirst
and another with the constraint
where T : ISecond
You now want T to be a class that implements both IFirst and ISecond.
Concrete code example:
public interface IFirst
{
void F();
}
public interface ISecond
{
void S();
}
// Should the compiler pick this "overload"?
public class My<T> where T : IFirst
{
}
// Or this one?
public class My<T> where T : ISecond
{
}
public class Foo : IFirst, ISecond
{
public void Bar()
{
My<Foo> myFoo = new My<Foo>();
}
public void F() { }
public void S() { }
}
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).
I saw the following usage of in:
Covariance and contravariance real world example
interface IGobbler<in T> {
void gobble(T t);
}
I don't understand what the usage of in stands for. Does it have relationship with ref, out??
The in and out modifiers in 4.0 are necessary to enforce (or rather: enable) covariance and contravariance.
If you add in, you are only allowed to use T in inwards (contravariant) positions - so things like Add(T obj) is fine, but T this[int index] {get;} is not as this is an outwards (covariant) position.
This is essential for the variance features in 4.0. With variance, ref and out are both unavailable (they are both, and as such: neither).
Ignore what you know about ref and out because it's unrelated to this context. In this case in means that the T will only appear on the right hand side of function names (i.e. in formal parameter lists like void gobble(T t)). If it said out, then T would only appear to the left of function names (i.e. return values like T foo(int x)). The default (not specifying anything) allows T to appear in either place.
In C# 4.0, Contravariance allows for
example, IComparer<X> to be cast to
IComparer<Y> even if Y is a derived
type of X. To achieve this IComparer
should be marked with the In modifier.
public interface IComparer<in T> {
public int Compare(T left, T right);
}
Have look here for example and explanation:
http://www.csharphelp.com/2010/02/c-4-0-covariance-and-contravariance-of-generics/
The in modifier tells you that the type is contravariant and can be implicitly converted to a narrower type. Notice in the example below that even though gobble takes a Shape, it can be assigned to an Action<Rectangle> because we've declared it to be contravariant. This is because anyone calling the delegate and passing it a Rectangle can obviously also pass the Rectangle to a method that takes a Shape as well.
There are some rules for when you use in, and out, but that's what it enables in a nutshell.
For example:
public class Shape { }
public class Rectangle : Shape { }
public interface IGobbler<Shape>
{
void gobble(Shape shape);
}
public class Gobbler : IGobbler<Shape>
{
public void gobble(Shape r) { }
}
public static class Program
{
public static void Main()
{
var g = new Gobbler();
// notice can implictly convert to a narrower type because of the 'in' keyword
Action<Rectangle> r = g.gobble;
}
}
the in and out does not have anything to do with ref and out.
The in keyword is used to describe that in instance of the interface will consume an instance of T. In the example you linked the line
IGobbler<Donkey> dg = new QuadrupedGobbler();
creates a gobbler that you can feed Donkeys to, eventhough the Donkey isn't a QuadrupledCreature, but it derives from it. So you are able to use a more specialized instance instead of the base class as argument.
The out keyword works much the same way, except it's used to describe a thing that produces stuff instead of comsuming it.
In the same example, the line
ISpewer<Rodent> rs = new MouseSpewer();
creates an ISpewer, which when called spews a mouse. A mouse is not a rodent, but derives from it, so you are able to use a producing class that produces more specialized instance than what the interface declares.
Notice how the way the most specialized class is swapped in the two cases. When using the in keyword, you use the specialized class as the generic argument on the interface, whereas in the out case, you use the base class as the generic argument to tell the compiler, that eventhough you create a more specialized class, it should treat it like the base class.
I like to think of it as consumption and production, as these are familiar metaphors for most developers. A method that takes an IGobbler<Cow> can also accept an IGobbler<Animal>, because a Gobbler that can gobble (consume) any Animal can also gobble a Cow. The Gobbler here is a consumer of a specific type of Animal, so it uses the in tag.
The above case (contravariance) can seem counter-intuitive, but think about it from the perspective of the RestaurantOwner who wants a Gobbler<Cow>. If a Gobbler will only gobble Pigs and the RestaurantOwner tries to feed him a Cow, it won't work. He can only accept Gobblers that are less picky, so a Gobbler<Animal> or Gobbler<Herbivore> works fine.
On the other hand, suppose you have a Farmer<Animal> that sells Animals (having a Farm method that returns IEnumerable<Animal>.) If you have a Purchaser that wants to Buy(IEnumerable<Animal>), then it can accept Farmer<Cow>.Farm(), as the Purchaser is willing to buy any produced Animal and Cows are Animals. The Farmer here is a producer of a specific type of Animal, so it uses the `out' tag.
The IN keyword tells the compiler that we only want to use T as an input value.
It will not allow casting from say, IGobbler to IGobbler
Suppose I have two classes:
class a
{
public void sayGoodbye() { Console.WriteLine("Tschüss"); }
public virtual void sayHi() { Console.WriteLine("Servus"); }
}
class b : a
{
new public void sayGoodbye() { Console.WriteLine("Bye"); }
override public void sayHi() { Console.WriteLine("Hi"); }
}
If I call a generic method that requires type 'T' to be derived from class 'a':
void call<T>() where T : a
Then inside that method I call methods on an instance of type 'T' the method call are bound to type 'a', as if the instance was being cast as 'a':
call<b>();
...
void call<T>() where T : a
{
T o = Activator.CreateInstance<T>();
o.sayHi(); // writes "Hi" (virtual method)
o.sayGoodbye(); // writes "Tschüss"
}
By using reflection I am able to get the expected results:
call<b>();
...
void call<T>() where T : a
{
T o = Activator.CreateInstance<T>();
// Reflections works fine:
typeof(T).GetMethod("sayHi").Invoke(o, null); // writes "Hi"
typeof(T).GetMethod("sayGoodbye").Invoke(o, null); // writes "Bye"
}
Also, by using an interface for class 'a' I get the expected results:
interface Ia
{
void sayGoodbye();
void sayHi();
}
...
class a : Ia // 'a' implements 'Ia'
...
call<b>();
...
void call<T>() where T : Ia
{
T o = Activator.CreateInstance<T>();
o.sayHi(); // writes "Hi"
o.sayGoodbye(); // writes "Bye"
}
The equivalent non-generic code also works fine:
call();
...
void call()
{
b o = Activator.CreateInstance<b>();
o.sayHi(); // writes "Hi"
o.sayGoodbye(); // writes "Bye"
}
Same thing if I change the generic constraint to 'b':
call<b>();
...
void call<T>() where T : b
{
T o = Activator.CreateInstance<T>();
o.sayHi(); // writes "Hi"
o.sayGoodbye(); // writes "Bye"
}
It seems that the compiler is generating method calls to the base class specified in the constraint, so I guess I understand what is happening, but this is not what I expected. Is this really the correct result?
Generics aren't C++ Templates
Generics are a general type: there will be only one generic class (or method) output by the compiler. Generics doesn't work by compile-time replacing T with the actual type provided, which would require compiling a separate generic instance per type parameter but instead works by making one type with empty "blanks". Within the generic type the compiler then proceeds to resolve actions on those "blanks" without knowledge of the specific parameter types. It thus uses the only information it already has; namely the constraints you provide in addition to global facts such as everything-is-an-object.
So when you say...
void call<T>() where T : a {
T o = Activator.CreateInstance<T>();
o.sayGoodbye();//nonvirtual
...then type T of o is only relevant at compile time - the runtime type may be more specific. And at compile time, T is essentially a synonym for a - after all, that's all the compiler knows about T! So consider the following completely equivalent code:
void call<T>() where T : a {
a o = Activator.CreateInstance<T>();
o.sayGoodbye();//nonvirtual
Now, calling a non-virtual method ignores the run-time type of a variable. As expected, you see that a.sayGoodbye() is called.
By comparison, C++ templates do work the way you expect - they actually expand the template at compile time, rather than making a single definition with "blanks", and thus the specific template instances can use methods only available to that specialization. As a matter of fact, even at run-time, the CLR avoids actually instantiating specific instances of templates: since all the calls are either virtual (making explicit instantiation unnecessary) or non-virtual to a specific class (again, no point in instantiating), the CLR can use the same bytes - probably even the same x86 code - to cover multiple types. This isn't always possible (e.g. for value types), but for reference types that saves memory and JIT-time.
Two more things...
Firstly, your call method uses Activator - that's not necessary; there's an exceptional constraint new() you may use instead that does the same thing but with compile-time checking:
void call<T>() where T : a, new() {
T o = new T();
o.sayGoodbye();
Attempting to compile call<TypeWithoutDefaultConstructor>() will fail at compile time with human-readable message.
Secondly, it may seem as though generics are largely pointless if they're just blanks - after all, why not simply work on a-typed variables all along? Well, although at compile-time you can't rely on any details a sub-class of a might have within the generic method, you're still enforcing that all T are of the same subclass, which allows in particular the usage of the well-known containers such as List<int> - where even though List<> can never rely on int internals, to users of List<> it's still handy to avoid casting (and related performance and correctness issues).
Generics also allow richer constraints than normal parameters: for example, you can't normally write a method that requires its parameter to be both a subtype of a and IDisposable - but you can have several constraints on a type parameter, and declare a parameter to be of that generic type.
Finally, generics may have run-time differences. Your call to Activator.CreateInstance<T>() is a perfect illustration of that, as would be the simple expression typeof(T) or if(myvar is T).... So, even though in some sense the compiler "thinks" of the return type of Activator.CreateInstance<T>() as a at compile time, at runtime the object will be of type T.
sayGoodbye is not virtual.
The compiler only "knows" T is of type a. It will call sayGoodbye on a.
On type b you redefine sayGoodbye, but the compiler is not aware of type b. It cannot know all derivates of a. You can tell the compiler that sayGoodbye may be overriden, by making it virtual. This will cause the compiler to call sayGoodbye on a special way.
Method hiding is not the same as polymorphism, as you've seen. You can always call the A version of the method simply by downcasting from B to A.
With a generic method, with T constrained to type A, there is no way for the compiler to know whether it could be some other type, so it would be very unexpected, in fact, for it to use a hiding method rather than the method defined on A. Method hiding is for convenience or interoperability; it has nothing to do with substituting behavior; for that, you need polymorphism and virtual methods.
EDIT:
I think the fundamental confusion here is actually Generics vs. C++ style templates. In .NET, there is only one base of code for the generic type. Creating a specialized generic type does not involve emitting new code for the specific type. This is different from C++, where a template specialization involves actually creating and compiling additional code, so that it will be truly specialized for the type specified.
The new keyword is kind of a hack in C#. It contradicts polymorphism, because the method called depends on the type of the reference you hold.