Which is the preferred syntax for a Generic Class Derivation Constraint? - c#

The documented derivation constraint uses a where T : clause and the sample code that I'm tinkering with is
public class TwoThingsIPC<T> where T : IPassClass
{ ...
}
where IPassClass is an interface.
Code from a third-party that I am using has the format
public class TwoThingsIPC<IPassClass>
{ ...
}
Both result in the same behaviour in my code, but are they the same and if not what is the difference?

They are not the same. The second declaration is misleading:
public class TwoThingsIPC<IPassClass>
{ ...
}
does not constrain the type to the IPassClass interface. It uses a poor choice of names for a generic argument. There's nothing preventing you from creating an instance of TwoThingsIPC<int> - the IPassClass references in the class's code would just be "replaced" by int.1
On the other hand, a variable of type TwoThingsIPC<IPassClass>, for example:
TwoThingsIPC<IPassClass> myVar = new TwoThingsIPC<IPassClass>();
does constrain the type to the IPassClass interface.
1 That's not what really happens, but I don't have a better explanation yet.

Your example is wrong. An identifier is an identifier, and T and IPassClass are both just identifiers. What's in a name? So:
public class TwoThingsIPC<IPassClass>
is really the same as:
public class TwoThingsIPC<T>
except in the first case you use a really confusing name for the type parameter you declare there.
Maybe you were thinking of another situation where you will find yourself choosing between:
public class AnotherClass : TwoThingsIPC<IPassClass>
and:
public class AnotherClass<TPass> : TwoThingsIPC<TPass>
where TPass : IPassClass
where in both cases IPassClass must be a type that is already declared elsewhere.
Note that the first of these is a non-generic class that has a generic class as its base class. The second one is a generic class (since TPass which is declared there is its type parameter) which has a base class that depends on its own generic parameter.

In a generic type definition, the where clause is used to specify constraints on the types that can be used as arguments for a type parameter defined in a generic declaration.
In addition to interface constraints, a where clause can include a base class constraint, which states that a type must have the specified class as a base class (or be that class itself) in order to be used as a type argument for that generic type
If you want to examine an item in a generic list to determine whether it is valid or to compare it to some other item, the compiler must have some guarantee that the operator or method it has to call will be supported by any type argument that might be specified by client code. This guarantee is obtained by applying one or more constraints to your generic class definition.
References:
http://msdn.microsoft.com/en-us/library/bb384067.aspx
http://msdn.microsoft.com/en-us/library/d5x73970.aspx

The 'where' is a generic type constraint.
Taken from http://msdn.microsoft.com/en-us/library/bb384067.aspx
In a generic type definition, the where clause is used to specify
constraints on the types that can be used as arguments for a type
parameter defined in a generic declaration. For example, you can
declare a generic class, MyGenericClass, such that the type parameter
T implements the IComparable interface:
Here are some examples:
public class TwoThingsIPC<T> where T : IPassClass
{
}
public class TestClass
{
}
public class TestClass2 : IPassClass
{
}
var test1 = new TwoThingsIPC<TestClass>(); //this will not compile
var test2 = new TwoThingsIPC<TestClass2>(); //this will compile because it implements IPassClass
Other examples:
public class TwoThingsIPC<T> where T : class
{
}
public class TestClass
{
}
var test1 = new TwoThingsIPC<int>(); //this will not compile because it is a value type
//these will compile because they are reference types
var test2 = new TwoThingsIPC<TestClass>();
var test3 = new TwoThingsIPC<List<TestClass>>();
internal delegate void DWork();
var test4 = new TwoThingsIPC<DWork>();
References:
http://msdn.microsoft.com/en-us/library/bb384067.aspx
http://msdn.microsoft.com/en-us/library/d5x73970.aspx

Thanks for the help; to put together the pertinent responses and to make sure I have the facts correct:
The Asawyer comment to the original post points out the difference between a constraint and argument for generics ... while D Stanly illustrates how using an argument where a constraint is required can lead to sloppy type matching.
Jeppe Stig Nielsen figured out that I soon will want to write classes that inherit from the generic class with an interface argument. I have asked him where to find examples of how to do that.
All together solid support to get going with some dependency injection...
Thanks again!

Related

How to enforce interface generics' rules on inherited type? [duplicate]

Item class
public class Item
{
public bool Check(int value) { ... }
}
Base abstract class with generic type constraint
public abstract class ClassBase<TItem>
where TItem : Item
{
protected IList<TItem> items;
public ClassBase(IEnumerable<TItem> items)
{
this.items = items.ToList();
}
public abstract bool CheckAll(int value);
}
Inherited class without constraints
public class MyClass<TItem> : ClassBase<TItem>
{
public override bool CheckAll(int value)
{
bool result = true;
foreach(TItem item in this.items)
{
if (!item.Check(value)) // this doesn't work
{
result = false;
break;
}
}
return result;
}
}
I would like to know why aren't generic type constraints inheritable? Because if my inherited class inherits from base class and passes over its generic type which has a constraint on the base class it automatically means that generic type in inherited class should have the same constraint without explicitly defining it. Shouldn't it?
Am I doing something wrong, understanding it wrong or is it really that generic type constraint aren't inheritable? If the latter is true, why in the world is that?
A bit of additional explanation
Why do I think that generic type constraints defined on a class should be inherited or enforced on child classes? Let me give you some additional code to make it bit less obvious.
Suppose that we have all three classes as per above. Then we also have this class:
public class DanteItem
{
public string ConvertHellLevel(int value) { ... }
}
As we can see this class does not inherit from Item so it can't be used as a concrete class as ClassBase<DanteItem> (forget the fact that ClassBase is abstract for now. It could as well be a regular class). Since MyClass doesn't define any constraints for its generic type it seems perfectly valid to have MyClass<DanteItem>...
But. This is why I think generic type constraints should be inherited/enforced on inherited classes just as with member generic type constraints because if we look at definition of MyClass it says:
MyClass<T> : ClassBase<T>
When T is DanteItem we can see that it automatically can't be used with MyClass because it's inherited from ClassBase<T> and DanteItem doesn't fulfill its generic type constraint. I could say that **generic type on MyClass depends on ClassBase generic type constraints because otherwise MyClass could be instantiated with any type. But we know it can't be.
It would be of course different when I would have MyClass defined as:
public class MyClass<T> : ClassBase<Item>
in this case T doesn't have anything to to with base class' generic type so it's independent from it.
This is all a bit long explanation/reasoning. I could simply sum it up by:
If we don't provide generic type constraint on MyClass it implicitly implies that we can instantiate MyClass with any concrete type. But we know that's not possible, since MyClass is inherited from ClassBase and that one has a generic type constraint.
I hope this makes much more sense now.
ANOTHER UPDATE:
This question was the subject of my blog in July 2013. Thanks for the great question!
UPDATE:
I've given this some more thought and I think the problem is that you don't want inheritance at all. Rather, what you want is for all constraints that must be placed on a type parameter in order for that type parameter to be used as a type argument in another type to be automatically deduced and invisibly added to the declaration of the type parameter. Yes?
Some simplified examples:
class B<T> where T:C {}
class D<U> : B<U> {}
U is a type parameter that is used in a context where it must be C. Therefore in your opinion the compiler should deduce that and automatically put a constraint of C on U.
What about this?
class B<T, U> where T : X where U : Y {}
class D<V> : B<V, V> {}
Now V is a type parameter used in a context where it must be both X and Y. Therefore in your opinion the compiler should deduce that and automatically put a constraint of X and Y on V. Yes?
What about this?
class B<T> where T : C<T> {}
class C<U> : B<D<U>> where U : IY<C<U>> {}
class D<V> : C<B<V>> where V : IZ<V> {}
I just made that up, but I assure you that it is a perfectly legal type hierarchy. Please describe a clear and consistent rule that does not go into infinite loops for determining what all the constraints are on T, U and V. Don't forget to handle the cases where type parameters are known to be reference types and the interface constraints have covariance or contravariance annotations! Also, the algorithm must have the property that it gives exactly the same results no matter what order B, C and D appear in source code.
If inference of constraints is the feature you want then the compiler has to be able to handle cases like this and give clear error messages when it cannot.
What is so special about base types? Why not actually implement the feature all the way?
class B<T> where T : X {}
class D<V> { B<V> bv; }
V is a type parameter used in a context where it must be convertible to X; therefore the compiler should deduce this fact and put a constraint of X on V. Yes? Or no?
Why are fields special? What about this:
class B<T> { static public void M<U>(ref U u) where U : T {} }
class D<V> : B<int> { static V v; static public void Q() { M(ref v); } }
V is a type parameter used in a context where it can only be int. Therefore the C# compiler should deduce this fact and automatically put a constraint of int on V.
Yes? No?
You see where this is going? Where does it stop? In order to implement your desired feature properly the compiler must do whole-program analysis.
The compiler does not do this level of analysis because that is putting the cart before the horse. When you construct a generic, you are required to prove to the compiler that you've satisfied the constraint. It's not the compiler's job to figure out what you meant to say and work out what further set of constraints satisfy the original constraint.
For similar reasons, the compiler also does not attempt to automatically infer variance annotations in interfaces on your behalf. See my article on that subject for details.
http://blogs.msdn.com/b/ericlippert/archive/2007/10/29/covariance-and-contravariance-in-c-part-seven-why-do-we-need-a-syntax-at-all.aspx
Original answer:
I would like to know why aren't generic type constraints inheritable?
Only members are inherited. A constraint is not a member.
if my inherited class inherits from base class and passes over its generic type which has a constraint on the base class it automatically means that generic type in inherited class should have the same constraint without explicitly defining it. Shouldn't it?
You're just asserting how something should be, without providing any explanation of why it should be that way. Explain to us why you believe that the world should be that way; what are the benefits and what are the drawbacks and what are the costs?
Am I doing something wrong, understanding it wrong or is it really that generic type constraint aren't inheritable?
Generic constraints are not inherited.
If the latter is true, why in the world is that?
Features are "not implemented" by default. We don't have to provide a reason why a feature is not implemented! Every feature is not implemented until someone spends the money to implement it.
Now, I hasten to note that generic type constraints are inherited on methods. Methods are members, members are inherited, and the constraint is a part of the method (though not part of its signature). So the constraint comes along with the method when it is inherited. When you say:
class B<T>
{
public virtual void M<U>() where U : T {}
}
class D<V> : B<IEnumerable<V>>
{
public override void M<U>() {}
}
Then D<V>.M<U> inherits the constraint and substitutes IEnumerable<V> for T; thus the constraint is that U must be convertible to IEnumerable<V>. Note that C# does not allow you to restate the constraint. This is in my opinion a misfeature; I would like to be able to restate the constraint for clarity.
But D does not inherit any kind of constraint on T from B; I don't understand how it possibly could. M is a member of B, and is inherited by D along with its constraint. But T is not a member of B in the first place, so what is there to inherit?
I'm really not understanding at all what feature it is that you want here. Can you explain with more details?
Below is a scenario where the implicit nature of this behavior causes different behavior than expected:
I recognize that this scenario may seem extravagant in the amount of setup, but this is just one example of where this behavior might cause a problem. Software applications can be complicated, so even though this scenario may seem complicated, I wouldn't say that this can't happen.
In this example there is an Operator class that implements two similar interfaces: IMonitor and IProcessor. Both have a start method and an IsStarted property, but the behavior for each interface within the Operator class is separate. I.e. there is a _MonitorStarted variable and a _ProcessorStarted variable within the Operator class.
MyClass<T> derives from ClassBase<T>. ClassBase has a type constraint on T that it must implement the IProcessor interface, and according to the suggested behavior MyClass inherits that type constraint.
MyClass<T> has a Check method, which is built with the assumption that it can get the value of the IProcessor.IsStarted property from the inner IProcessor object.
Suppose someone changes the implementation of ClassBase to remove the type constraint of IProcessor on the generic parameter T and replace it with a type contraint of IMonitor. This code will silently work, but will produce different behavior. The reason is because the Check method in MyClass<T> is now calling the IMonitor.IsStarted property instead of the IProcessor.IsStarted property, even though the code for MyClass<T> hasn't changed at all.
public interface IMonitor
{
void Start();
bool IsStarted { get; }
}
public interface IProcessor
{
void Start();
bool IsStarted { get; }
}
public class Operator : IMonitor, IProcessor
{
#region IMonitor Members
bool _MonitorStarted;
void IMonitor.Start()
{
Console.WriteLine("IMonitor.Start");
_MonitorStarted = true;
}
bool IMonitor.IsStarted
{
get { return _MonitorStarted; }
}
#endregion
#region IProcessor Members
bool _ProcessorStarted;
void IProcessor.Start()
{
Console.WriteLine("IProcessor.Start");
_ProcessorStarted = true;
}
bool IProcessor.IsStarted
{
get { return _ProcessorStarted; }
}
#endregion
}
public class ClassBase<T>
where T : IProcessor
{
protected T Inner { get; private set; }
public ClassBase(T inner)
{
this.Inner = inner;
}
public void Start()
{
this.Inner.Start();
}
}
public class MyClass<T> : ClassBase<T>
//where T : IProcessor
{
public MyClass(T inner) : base(inner) { }
public bool Check()
{
// this code was written assuming that it is calling IProcessor.IsStarted
return this.Inner.IsStarted;
}
}
public static class Extensions
{
public static void StartMonitoring(this IMonitor monitor)
{
monitor.Start();
}
public static void StartProcessing(this IProcessor processor)
{
processor.Start();
}
}
class Program
{
static void Main(string[] args)
{
var #operator = new Operator();
#operator.StartMonitoring();
var myClass = new MyClass<Operator>(#operator);
var result = myClass.Check();
// the value of result will be false if the type constraint on T in ClassBase<T> is where T : IProcessor
// the value of result will be true if the type constraint on T in ClassBase<T> is where T : IMonitor
}
}
I think you're confused becuase you're declaring you derived class with TItem as well.
If you think about it if you were using Q instead so.
public class MyClass<Q> : BaseClass<Q>
{
...
}
Then how is it to be determined that Q is of the type item?
You need to add the constraint to the derived classes Generic Type as well so
public class MyClass<Q> : BaseClass<Q> were Q : Item { ... }
Because the ClassBase has a constraint on his template (should by typeof Item), you have to add this constraint to MyClass too.
If you don't do this, you could create a new instance of MyClass, where the template isn't a type of Item. When creating the base class, it will fail.
[edit]
Hmm now a re-read your question, and I see your code does compile? Ok.
Well, im MyClass you don't know the basetype of this.items, so you can't call the Check method.
this.items is of the type IList, and in your class, TItem isn't specified, thats why the class doesn't understand the Check method.
Let me counter your question, why don't you want to add the constraint to your MyClass class? Given any other class type as template to this class, would result in an error. Why not prevent this errors by adding a constraint so it will fail compiletime.

Restricting 'Type' parameters in a method/constructor

I'd like to pass a Type parameter into a constructor. This constructor belongs to an attribute.
That's simple. But how do I constrain this Type parameter to sub classes of a particular class only?
So I have a parent class ParentClass and two child classes MyChildClass : ParentClass and MyOtherChildClass : ParentClass.
My attribute looks like this:
public class AssociatedTypeAttribute : Attribute
{
private readonly Type _associatedType;
public Type AssociatedType => _associatedType;
public AssociatedTypeAttribute(Type associatedType)
{
if (!associatedType.IsSubclassOf(typeof(ParentClass)))
throw new ArgumentException($"Specified type must be a {nameof(Parentclass)}, {associatedType.Name} is not.");
_associatedType = associatedType;
}
}
This works, and at runtime it'll throw an exception if the type isn't a ParentClass - but runtime is too late.
Is it possible to add some sort of constraint? Can I use generics here or am I right in saying generics are out of bounds since it's the constructor of an attribute?
Note usage:
public enum MyEnum
{
[AssociatedType(typeof(MyChildClass))]
MyEnumValue,
[AssociatedType(typeof(MyOtherChildClass))]
MyOtherEnumValue
}
You can't do this with Type and you can't use generics because it is not allowed to extend Attribute with a generic class.
The best solution you have is a runtime check and simply ignoring the attribute if the target doesn't match the intended one.

Compiler Issue with Generics and Inheritance

I have 2 classes with the following declarations:
abstract class ClassBase<T, S> where T : myType where S : System.Data.Objects.DataClasses.EntityObject
abstract class ServiceBase<T> where T : myType
and I have 2 other classes, that inherit one from each, we can call ClassInherited and ServiceInherited. Note that the two Service classes are not in the same project as the other two.
The idea is that in the ServiceBase class I can declare a property like protected ClassBase<T,System.Data.Objects.DataClasses.EntityObject> Class { get; set; } and then in the inherited service`s constructor something like this.Class = ClassInheritedInstance
I already implemented the idea but it gives me this error when assigning the Class property in the ServiceInherited class constructor:
Cannot implicitly convert type 'ClassInherited' to 'ClassBase< T, S>'
Note that ClassInherited is indeed an specification of Class<T,S>... it's just that the compiler doesn't seem to be able to tell the types correctly. Also changing the declaration of the class property to protected ClassBase<T, EntityObjectInherited> works, and EntityObjectInherited is an implementation of System.Data.Objects.DataClasses.EntityObject... I don't see why is there a problem.
Update 1
Note that at compile time the type of ClassInherited is known, as its declaration is public class ClassInherited : ClassBase<myTypeInherited, EntityObjectInherited>
INITIAL ANSWER
The reason that you cannot use protected ClassBase<T,S> Class { get; set; } in the ServiceInherited-class is that you do not know the S-type that is needed to declare a type of the property Class.
You have to options:
Include the S type in the specification of the Service-type: abstract class ServiceBase<T, S> where T : myType where S : System.Data.Objects.DataClasses.EntityObject
Implement an interface for ClassBase with only the T-type, so that you can refer to a class-inherited-object without using the S-type. Then you CAN have a property in the service class (of the interface-type), since you do not need to specify the S-type.
Note that generic-type-checking is not checked at run-time, but at compile-time. Else it wouldn't be strong-typing.
UPDATE
The reason the cast won't work is that type ClassBase<T, EntityObjectInherited> is not equal or castable to ClassBase<T, System.Data.Objects.DataClasses.EntityObject>. Covariance doesn't work on class-types, only on interface-types.
I think the solution here is to work with interfaces. Use an interface for class-base, say IClassBase<T>. That way you can omit the S-type in the signature of the class, and only have it in the interface.
UPDATE (2)
One thing you can do is to create an interface for the Class property. You can define the following interface.
public interface IClass<T> where T : myType {
// TODO
// Define some interface definition, but you cannot use the
// EntityObject derived class, since they are not to be known
// in the service class.
}
If you implement this interface on your ClassBase class, and add a constructor on your ServiceBase class which accepts an object of type IClass, then you can push this object to property Class in the base-class. Like this:
public abstract class ClassBase<T, S> : IClass<T>
where T : MyType
where S : EntityObject {
}
public abstract class ServiceBase<T> where T : MyType {
protected ServiceBase(IClass<T> classObject) {
Class = classObject;
}
protected IClass<T> Class { get; set; }
}
public class ServiceInherited : ServiceBase<MyTypeDerived> {
public ServiceInherited(IClass<MyTypeDerived> classObject)
: base(classObject) {
}
}
One thing to note, is not to expose the S-type of the ClassBase to the interface. Since you do not want the Service-classes to know this type, they cannot actively call any methods or use properties that somehow have the S-type in their definition.
This ugly boxing, unboxing should work :
Class = (ClassBase<T, S>)(object)new ClassInherited();
Covariance is allowed only with generic interface today ?MSDN
This works :
// Covariance.
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
This doesn't :
List<string> strings = new List<string>();
List<object> objects = strings;
The compiler won't be able to guess that ClassInherited is indeed a correct match for ClassBase<T, S> as it does not know the exact types of T and S, that will be decided at generics type instanciation at runtime.
So if you're sure that at runtime the types will be compatible you can safely try a cast :
Class = ClassInheritedInstance as ClassBase<T, S>
This will only have a slight (not to say negligible) overhead as the CLR will need to check the compatibility of the types to have safe code.

Why aren't generic type constraints inheritable/hierarchically enforced

Item class
public class Item
{
public bool Check(int value) { ... }
}
Base abstract class with generic type constraint
public abstract class ClassBase<TItem>
where TItem : Item
{
protected IList<TItem> items;
public ClassBase(IEnumerable<TItem> items)
{
this.items = items.ToList();
}
public abstract bool CheckAll(int value);
}
Inherited class without constraints
public class MyClass<TItem> : ClassBase<TItem>
{
public override bool CheckAll(int value)
{
bool result = true;
foreach(TItem item in this.items)
{
if (!item.Check(value)) // this doesn't work
{
result = false;
break;
}
}
return result;
}
}
I would like to know why aren't generic type constraints inheritable? Because if my inherited class inherits from base class and passes over its generic type which has a constraint on the base class it automatically means that generic type in inherited class should have the same constraint without explicitly defining it. Shouldn't it?
Am I doing something wrong, understanding it wrong or is it really that generic type constraint aren't inheritable? If the latter is true, why in the world is that?
A bit of additional explanation
Why do I think that generic type constraints defined on a class should be inherited or enforced on child classes? Let me give you some additional code to make it bit less obvious.
Suppose that we have all three classes as per above. Then we also have this class:
public class DanteItem
{
public string ConvertHellLevel(int value) { ... }
}
As we can see this class does not inherit from Item so it can't be used as a concrete class as ClassBase<DanteItem> (forget the fact that ClassBase is abstract for now. It could as well be a regular class). Since MyClass doesn't define any constraints for its generic type it seems perfectly valid to have MyClass<DanteItem>...
But. This is why I think generic type constraints should be inherited/enforced on inherited classes just as with member generic type constraints because if we look at definition of MyClass it says:
MyClass<T> : ClassBase<T>
When T is DanteItem we can see that it automatically can't be used with MyClass because it's inherited from ClassBase<T> and DanteItem doesn't fulfill its generic type constraint. I could say that **generic type on MyClass depends on ClassBase generic type constraints because otherwise MyClass could be instantiated with any type. But we know it can't be.
It would be of course different when I would have MyClass defined as:
public class MyClass<T> : ClassBase<Item>
in this case T doesn't have anything to to with base class' generic type so it's independent from it.
This is all a bit long explanation/reasoning. I could simply sum it up by:
If we don't provide generic type constraint on MyClass it implicitly implies that we can instantiate MyClass with any concrete type. But we know that's not possible, since MyClass is inherited from ClassBase and that one has a generic type constraint.
I hope this makes much more sense now.
ANOTHER UPDATE:
This question was the subject of my blog in July 2013. Thanks for the great question!
UPDATE:
I've given this some more thought and I think the problem is that you don't want inheritance at all. Rather, what you want is for all constraints that must be placed on a type parameter in order for that type parameter to be used as a type argument in another type to be automatically deduced and invisibly added to the declaration of the type parameter. Yes?
Some simplified examples:
class B<T> where T:C {}
class D<U> : B<U> {}
U is a type parameter that is used in a context where it must be C. Therefore in your opinion the compiler should deduce that and automatically put a constraint of C on U.
What about this?
class B<T, U> where T : X where U : Y {}
class D<V> : B<V, V> {}
Now V is a type parameter used in a context where it must be both X and Y. Therefore in your opinion the compiler should deduce that and automatically put a constraint of X and Y on V. Yes?
What about this?
class B<T> where T : C<T> {}
class C<U> : B<D<U>> where U : IY<C<U>> {}
class D<V> : C<B<V>> where V : IZ<V> {}
I just made that up, but I assure you that it is a perfectly legal type hierarchy. Please describe a clear and consistent rule that does not go into infinite loops for determining what all the constraints are on T, U and V. Don't forget to handle the cases where type parameters are known to be reference types and the interface constraints have covariance or contravariance annotations! Also, the algorithm must have the property that it gives exactly the same results no matter what order B, C and D appear in source code.
If inference of constraints is the feature you want then the compiler has to be able to handle cases like this and give clear error messages when it cannot.
What is so special about base types? Why not actually implement the feature all the way?
class B<T> where T : X {}
class D<V> { B<V> bv; }
V is a type parameter used in a context where it must be convertible to X; therefore the compiler should deduce this fact and put a constraint of X on V. Yes? Or no?
Why are fields special? What about this:
class B<T> { static public void M<U>(ref U u) where U : T {} }
class D<V> : B<int> { static V v; static public void Q() { M(ref v); } }
V is a type parameter used in a context where it can only be int. Therefore the C# compiler should deduce this fact and automatically put a constraint of int on V.
Yes? No?
You see where this is going? Where does it stop? In order to implement your desired feature properly the compiler must do whole-program analysis.
The compiler does not do this level of analysis because that is putting the cart before the horse. When you construct a generic, you are required to prove to the compiler that you've satisfied the constraint. It's not the compiler's job to figure out what you meant to say and work out what further set of constraints satisfy the original constraint.
For similar reasons, the compiler also does not attempt to automatically infer variance annotations in interfaces on your behalf. See my article on that subject for details.
http://blogs.msdn.com/b/ericlippert/archive/2007/10/29/covariance-and-contravariance-in-c-part-seven-why-do-we-need-a-syntax-at-all.aspx
Original answer:
I would like to know why aren't generic type constraints inheritable?
Only members are inherited. A constraint is not a member.
if my inherited class inherits from base class and passes over its generic type which has a constraint on the base class it automatically means that generic type in inherited class should have the same constraint without explicitly defining it. Shouldn't it?
You're just asserting how something should be, without providing any explanation of why it should be that way. Explain to us why you believe that the world should be that way; what are the benefits and what are the drawbacks and what are the costs?
Am I doing something wrong, understanding it wrong or is it really that generic type constraint aren't inheritable?
Generic constraints are not inherited.
If the latter is true, why in the world is that?
Features are "not implemented" by default. We don't have to provide a reason why a feature is not implemented! Every feature is not implemented until someone spends the money to implement it.
Now, I hasten to note that generic type constraints are inherited on methods. Methods are members, members are inherited, and the constraint is a part of the method (though not part of its signature). So the constraint comes along with the method when it is inherited. When you say:
class B<T>
{
public virtual void M<U>() where U : T {}
}
class D<V> : B<IEnumerable<V>>
{
public override void M<U>() {}
}
Then D<V>.M<U> inherits the constraint and substitutes IEnumerable<V> for T; thus the constraint is that U must be convertible to IEnumerable<V>. Note that C# does not allow you to restate the constraint. This is in my opinion a misfeature; I would like to be able to restate the constraint for clarity.
But D does not inherit any kind of constraint on T from B; I don't understand how it possibly could. M is a member of B, and is inherited by D along with its constraint. But T is not a member of B in the first place, so what is there to inherit?
I'm really not understanding at all what feature it is that you want here. Can you explain with more details?
Below is a scenario where the implicit nature of this behavior causes different behavior than expected:
I recognize that this scenario may seem extravagant in the amount of setup, but this is just one example of where this behavior might cause a problem. Software applications can be complicated, so even though this scenario may seem complicated, I wouldn't say that this can't happen.
In this example there is an Operator class that implements two similar interfaces: IMonitor and IProcessor. Both have a start method and an IsStarted property, but the behavior for each interface within the Operator class is separate. I.e. there is a _MonitorStarted variable and a _ProcessorStarted variable within the Operator class.
MyClass<T> derives from ClassBase<T>. ClassBase has a type constraint on T that it must implement the IProcessor interface, and according to the suggested behavior MyClass inherits that type constraint.
MyClass<T> has a Check method, which is built with the assumption that it can get the value of the IProcessor.IsStarted property from the inner IProcessor object.
Suppose someone changes the implementation of ClassBase to remove the type constraint of IProcessor on the generic parameter T and replace it with a type contraint of IMonitor. This code will silently work, but will produce different behavior. The reason is because the Check method in MyClass<T> is now calling the IMonitor.IsStarted property instead of the IProcessor.IsStarted property, even though the code for MyClass<T> hasn't changed at all.
public interface IMonitor
{
void Start();
bool IsStarted { get; }
}
public interface IProcessor
{
void Start();
bool IsStarted { get; }
}
public class Operator : IMonitor, IProcessor
{
#region IMonitor Members
bool _MonitorStarted;
void IMonitor.Start()
{
Console.WriteLine("IMonitor.Start");
_MonitorStarted = true;
}
bool IMonitor.IsStarted
{
get { return _MonitorStarted; }
}
#endregion
#region IProcessor Members
bool _ProcessorStarted;
void IProcessor.Start()
{
Console.WriteLine("IProcessor.Start");
_ProcessorStarted = true;
}
bool IProcessor.IsStarted
{
get { return _ProcessorStarted; }
}
#endregion
}
public class ClassBase<T>
where T : IProcessor
{
protected T Inner { get; private set; }
public ClassBase(T inner)
{
this.Inner = inner;
}
public void Start()
{
this.Inner.Start();
}
}
public class MyClass<T> : ClassBase<T>
//where T : IProcessor
{
public MyClass(T inner) : base(inner) { }
public bool Check()
{
// this code was written assuming that it is calling IProcessor.IsStarted
return this.Inner.IsStarted;
}
}
public static class Extensions
{
public static void StartMonitoring(this IMonitor monitor)
{
monitor.Start();
}
public static void StartProcessing(this IProcessor processor)
{
processor.Start();
}
}
class Program
{
static void Main(string[] args)
{
var #operator = new Operator();
#operator.StartMonitoring();
var myClass = new MyClass<Operator>(#operator);
var result = myClass.Check();
// the value of result will be false if the type constraint on T in ClassBase<T> is where T : IProcessor
// the value of result will be true if the type constraint on T in ClassBase<T> is where T : IMonitor
}
}
I think you're confused becuase you're declaring you derived class with TItem as well.
If you think about it if you were using Q instead so.
public class MyClass<Q> : BaseClass<Q>
{
...
}
Then how is it to be determined that Q is of the type item?
You need to add the constraint to the derived classes Generic Type as well so
public class MyClass<Q> : BaseClass<Q> were Q : Item { ... }
Because the ClassBase has a constraint on his template (should by typeof Item), you have to add this constraint to MyClass too.
If you don't do this, you could create a new instance of MyClass, where the template isn't a type of Item. When creating the base class, it will fail.
[edit]
Hmm now a re-read your question, and I see your code does compile? Ok.
Well, im MyClass you don't know the basetype of this.items, so you can't call the Check method.
this.items is of the type IList, and in your class, TItem isn't specified, thats why the class doesn't understand the Check method.
Let me counter your question, why don't you want to add the constraint to your MyClass class? Given any other class type as template to this class, would result in an error. Why not prevent this errors by adding a constraint so it will fail compiletime.

Generic class with method taking a different generic class

Sorry for asking what seems like such an obvious question.
I have an "adapter" generic class of type T where T is a defined interface. I want to create a method in that class which takes a different type of generic adapter.
public interface ICommon { }
public class TypeOne : ICommon { }
public class TypeTwo : ICommon { }
public class Adapter<T> where T : ICommon
{
void TakeAnotherType(Adapter<S> other)
{ }
}
This gives me a compilation error Cannot resolve symbol 'S'.
I would like to be able to do;
MyOne one = new Adapter<TypeOne>();
MyTwo two = new Adapter<TypeTwo>();
one.TakeAnotherType(two);
If I change the method to take Adapter<T> then it complains that "two" isn't of type Adapter<TypeOne>
void TakeAnotherType<S>(Adapter<S> other) where S:ICommon
{ }
Because the generic type T of Adapter is constrained to ICommon, it is important to also constrain S in the same way, as this is used as the generic type for Adapter<T>, so it must also satisfy the ICommon constraint.
Just change
void TakeAnotherType(Adapter<S> other)
into
void TakeAnotherType<S>(Adapter<S> other) where S : ICommon
and it should work.
Once you have specified that a class is generic (by naming it Something<T>), every method within it is implicitly generic on that type T. To say that a method is generic on a different type, you have to specify that fact in the method name, by calling it SomeMethod<U>. The body of this method will then have access to both types, T (the type that the class is generic on) and U (the class that the method is generic on).
Note also that the two usual conventions for type parameters are T, U, V etc; or TSomething, TSomethingElse, TEvenMore. I don't think I've ever seen S used...

Categories