Today my brain went dead, and I couldn't figure out a clean way of forcing the compiler to use inheritance for Generic inference.
Imagine the following 4 classes
Models
public abstract class Model
{
}
public class CodePerfModel : Model
{
}
Entities
public abstract class ModelEntity<TModel> where TModel : Model
{
public TModel Model { get; set; }
}
public class CodePerfEntity : ModelEntity<CodePerfModel>
{
}
Now to me logically I should take for granted that when I take something that inherits from ModelEntity<> (it will specify the type of TModel) via inheritance, because any class that inherits from ModelEntity<> will have to specify it.
Is there anyway to force the compiler to figure this out for me?
E.g.
If I currently want to use ModelEntity<>, I have to specify a type for it. Such as the following:
public class CallerClass<TEntity, TModel>
where TEntity : ModelEntity<TModel>
where TModel : Model
{
}
How can I get rid of the TModel argument everywhere? While still having access to the TModel type at compile time? E.g. via the base Model property.
To me, something like the following:
public class CallerClass<TEntity>
where TEntity : ModelEntity<>
{
}
Would make perfect sense as when calling it all I should have to speicfy is e.g.
SomeCall<CodePerfEntity>();
rather than
SomeCall<CodePerfEntity, CodePerfModel>();
Is this something that is currently possible?
Would this be worth raising for C# 6/7?
You mention you would like to access TModel at compilation time, while not explicitly specifying this type when deriving a class. Letting go of your example, and moving to a more general case, this means you would like the semantics to remain the same, however you would not like to explicitly declare the type parameter's own type parameters when declaring a generic constraint.
In essence, you are asking why a specific syntax sugar feature is not implemented.
Let's consider another example:
public class CallerX<A, B> where A : ModelEntity<> where B : ModelEntity<>
From the example in your question, the compiler should insert TModel'1 and TModel'2 as type parameters for A and B respectively. Let's say the feature is implemented. This means that we have created the default situation that TModel'1 and TModel'2 are different types, each having constraints that match the single type.
What if I would like to add more constraints to either TModel'1 or TModel'2, or force them to be the same type? Why is this case so special that it deserves its own syntax?
From what I know of the C# team, they have the policy that each new feature starts with "-100 points" and should be really great in order to be considered (see UserVoice for C#).
To summarize:
New language features are expensive and add complexity.
You are asking for an implicit syntax for which it is unlikely/unclear that it will be the desired situation in most of the cases.
Developers will have to learn and understand that an open generic type as a type parameter constraint will insert a hidden and anonymous extra parameter. To me, it is not intuitive that some other type parameter has been added to my type without me having declared it.
Related
Hey so I am trying to create a set of Generics and I cant seem to find the proper way to do this.
What I need is better showcased as an example implementation (which doesnt work):
public abstract class State<T,K> : StateMachine<StateType>{
public T Owner { get;set}
public Y Controller { get;set}
public void Setup(T Owner, Y Controller);
}
public abstract class StateMachine<StateType> where StateType : State<T,K>
where K : "MyOwnImplementationType typeof<this>??"// This refers to the "this" concrete type and not a special provided type, it since I cant seem to constraint to be the correct type, and inheritance type does not work
{
StateType[] states; // This needs to be the actual StateType and not the abstract class
public DoStuff(StateType t){
t.Setup(this, GetOwner()); // doesnt matter where Owner Comes from
}
}
public class ImplementationState : State<ImplementationStateMachine, ImplementationController> {
}
public class ImplementationStatemachine : StateMachine<ImplementationState, ImplementationController> {
}
If I replace MyOwnType with StateMachine, then it complains, and correctly, that my concrete implementation cant be mapped to the generic type.
I have been playing around with using interfaces and CoVariance/ ContraVariance but I cant seem to get the correct setup at all.
Is there anyway this is possible ?
Or any workaround how to setup this?
I am open to suggestions on another way to structure this sort of system.
The requirements is that I am able to access the correct types inside each class and not a generic variant.
The where clauses, apply to the items in the Generic declaration. The only way to do what you are trying to do is this:
public abstract class StateMachine<StateType, T, K>
where StateType: State<T,K>
where K: MyOwnType
From the C# Language specification
A class declaration cannot supply type_parameter_constraints_clauses unless it also supplies a type_parameter_list.
There can be at most one where clause for each type parameter, and the where clauses can be listed in any order
Infering from the in any order and for for each type parameter, it's evident that you need to declare the T,K in the class declaration, to apply any constraints on them.
Are there any real-world examples of using subtyping constraints on type parameters in .NET generics? By «subtyping constraints» I mean
where T : <base class name>
and
where T : U
May be there are some standard generics with corresponding constraints? Or specialized generic .NET-libraries.
UPD There are lots of good examples with interface constraints
where T : <interface name>
But subtyping constraints seems to be very specific and not so useful. I try to understand, in which cases this kind of constraints is really crucial. Luaan's answer contains examples with where T : <base class name> from ASP.NET MVC, but I am still interested in real-world examples with where T : U constraint.
I use them for a repository class in my data access layer e.g.
public interface IRepository<T>
where T : IDbItentity
{
IList<T> GetAll();
T GetById(int id);
int Insert(T saveThis);
void Update(T updateThis);
void Delete(T deleteThis);
}
Where IDBItentity is an interface as follows:
public interface IDbItentity
{
int Id { get; }
}
It's something you use a lot. In a way, it immitates the way normal inheritance works.
So for example, if you've got a common functionality built around O/RM entities, you can just create an entity base class, and use that as a type constraint in all the various data layers manipulating that entity.
Extremely useful is its use with interfaces.
And very often, you're going to write some kind of a wrapper around something else.
The basic idea is that you use those when you really only want the type parameter to fit some use case, but rather than just using the interface, you let the user of your code supply their concrete type. It still implements all the stuff you need to work correctly, but at the same time, the user can use all the features, even those you don't know about.
You will not find many cases in the BCL. Basically, this has to do with the fact that type constraints are constraints. The BCL usually uses generic types and methods to write very general functionality - I guess that's in part because of the fact that most of the BCL was there before generics, and because most of the time, inheritance will work just as well, if not better.
There's still differences, though. Say you need a collection of some entities. If you just use List<Entity>, you're saying "I expect any entity whatsoever, thanks". If you use List<T> where T : Entity (pseudocode), you're saying "I need to know the type you're giving me is an Entity, but I only want one kind of entity in the whole collection".
All in all, if you want good applications of generic type constraints, look at newer code. For example, in ASP.NET MVC, there's things like this:
public abstract class CachedAssociatedMetadataProvider<TModelMetadata>
: AssociatedMetadataProvider
where TModelMetadata : ModelMetadata
public class DataAnnotationsModelValidator<TAttribute>
: DataAnnotationsModelValidator
where TAttribute : ValidationAttribute
It's also very useful when you're using Actions (or events) to tag functionality to some such general class from the outside.
Again, the uses are basically such:
Constraint the types that can be used in your class
Ensure the type passed to you conforms to some contract
Improve useability for the users of your code
Performance optimization of value-types, mostly avoiding boxing - e.g. you can use IComparable without having to box the value
Often it is used for extension methods, for example:
public static string Parse<Tenum>(this object spr, int id) where Tenum : struct, IConvertible
{
Contract.Ensures(typeof(Tenum).IsEnum, "type must be is enum");
return ((Tenum)(object)id).ToString();
}
string ProductTypeTitle = this.Parse<ProductType>(product.ProductTypeID);
I am trying to work around a mocking issue by creating a custom mock of IDbSet.
The custom mock:
public class DbSetMock : IDbSet<Tenant>
{
/* hidden all other implemented methods/properties */
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, Tenant
{
throw new NotImplementedException();
}
}
The create method gives a build error that I have no clue on how to solve:
cannot specify both a constraint class and the 'class' or 'struct' constraint
Simply removing class from the constraints results in another build error (which I also don't understand :( ).
The constraints for type parameter 'TDerivedEntity' of method 'Tests.DAL.Tenants.DbSetMock.Create<TDerivedEntity>()' must match the constraints for type parameter 'TDerivedEntity' of interface method 'System.Data.Entity.IDbSet<BusinessLayer.DAL.Tenants.Tenant>.Create<TDerivedEntity>()'. Consider using an explicit interface implementation instead.
Can anybody help me successfully building this class?
Since the TDerived type parameter is constrained to be a Tenant, adding the constraints class or struct is redundant. Just remove the class constraint.
UPDATE: Curiously there seems to be a conflict between the compiler errors here. If you "fix" one you get the other, in an infinite loop of despair. Luckily, the second error also gives us a way out: you can use an explicit interface implementation:
public class DbSetMock : IDbSet<Tenant>
{
TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
{
throw new NotImplementedException();
}
}
There seems to be no way to implement that method without using explicit interface implementation. If you need it as part of the public interface of the class, I suggest creating another method that the interface implementation forwards to:
public class DbSetMock : IDbSet<Tenant>
{
TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
{
return Create<TDerivedEntity>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
{
throw new NotImplementedException();
}
}
Try to remove class from method part, like this;
public class DbSetMock : IDbSet<Tenant>
{
/* hidden all other implemented methods/properties */
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
{
throw new NotImplementedException();
}
}
class, Tenant is redundant code.
There are presently only three inheritable classes in the Framework whose descendants may be value types: Object, ValueType, and Enum. All three of those types are class types, but any type derived from ValueType or Enum will be a value type, and any type derived from Object which is not derived from ValueType will be a class type. With any type other than the above, a class or struct constraint would either be redundant or contradictory; not coincidentally, C# disallows constraints to be directly specified for the above types.
In some languages and frameworks, a prevailing design philosophy is that if there is a particular form of expression where the behavior that applies to that general form would be useless, there's no reason for the language/framework designer to go out of the way to forbid such a form. Under such a philosophy, it would be perfectly legal to have a generic type constrained to a sealed type (e.g. Fnord). Such a thing would be pointless if the type in question were sealed and no future version would ever be otherwise, but since applying the normal interpretation of generic constraints to such situation would yield reasonable behavior, and since there might conceivably be some situations where such constraints might be useful (e.g. writing code to use a class which is in development and is presently sealed, but may or may not be sealed in its final release, or writing code to interface with Reflection-based code that expects particular generic forms), the philosophy would suggest that constraining a generic type to a sealed class should be legal.
In some other languages and frameworks, a differing philosophy holds: if a programmer might expect some particular form of a construct to offer features beyond the general form but it does not, and if that particular form wouldn't seem very useful without such features, the language should forbid it, even if the construct would have a precise meaning which was well-defined and could not be expressed via other means if the implementers of the language don't see a reason for programmers to want to express that actual meaning.
The fact that neither C# nor .net has any problem with having one type parameter constrained to another, even when that other parameter is of a type that would not be accepted as a constraint, suggests that the restriction is artificially imposed by the language due to the aforementioned philosophy. It's unfortunate, IMHO, since there are many situations where it would be helpful to be able to say, e.g.
bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum
and even though .net would usefully allow such a construct, and even though the only obstacle which prevents C# from excepting it code to explicitly looks for such constraints so as to disallow them, the C# designers decided to forbid such constructs rather than allow them to behave as .net would interpret them (meaning that HasAnyFlags couldn't do anything directly with a T that it couldn't do with System.Enum, and using a T as a System.Enum would generally be no faster than using a System.Enum (sometimes slower), but T could nonetheless be useful for a couple reasons:
The method could enforce at compile time that the parameters must be the *same* enumerated type
The method could use a static class `EnumEvaluator` to generate and cache static delegates of type `Func`, such that `HasAnyFlags(T enum1, T enum2)` could be implemented as `return EnumEvaluator.HasAnyFlags(enum1,enum2);`. Such a function could be more than ten times as fast as `Enum.HasFlag`.
Still, useful as it might be to specify such constraints, the only way to specify them in C# is to have the C# source code specify some dummy type which could be used as a constraint, and then run the compiled code through a utility which will replace all references to the dummy type with references to the type one wanted to use in the first place.
It is telling you is that the constraint:
class, Tenant
is redundant. You can just remove class since Tenant is more constrained than class and includes class.
I have a C# class hierarchy with a common base type and two derived types. I want to declare an abstract method on the base class something like this :
public abstract IEnumerable<T> GetSiblings<T>() where T : MyBaseClass
... and I want this method to be implemented in the derived classes such that T is the type of that derived type, for each of the derived types, ie, in derived class A:
public override IEnumerable<A> GetSiblings<A>() { ... }
... and in derived class B ...
public override IEnumerable<B> GetSiblings<B>() { ... }
Put another way, each derived class must implement the method so that it returns an IEnumerable of items of the same type. Is there any way to implement this in C# ?
Well, you can hardly call a method generic if it only accepts a parameter of a single type, and your method signatures will have different return types which isn't allowed. Why don't you define an interface for all of these classes and simply return an IEnumerable<IMyClass>?
You can't do this because the return types are different. Simple as that. The reason is if you create an instance of A and stuff it into your base class(cast it) then the return type will be wrong.
You might be able to to use new instead but that might break your hierarchy.
This is not supported by the type system. It's a common enough problem, represented often as
class Animal<T> where T : Animal<T> { }
class Cat : Animal<Cat> { } // what you desire
class Dog : Animal<Cat> { } // what is possible yet not desired
But not a problem that has as yet been acted upon by the appropriate parties (be it the framework providers or C# team, not sure who).
Until it passes the critical "worth it" test as determined by costs (and opportunity costs) versus benefits, you'll have to work around it.
I found the solution. Apparently in C# 4.0, generic parameter types can be covariant, so what I've posted above will work. C# 3.5 or lower, and it doesn't work. Took a lot of Googling.
I think I finally get the point of constraints, but still a bit confused. Can someone tell me if the following is right?
Basically, if you inherit a class you may want to make sure that the class you inherit also inherits from some other class or some other interface.
It's confusing because presumably you would know that you would only want to inherit from a class that had the things you wanted but I guess with generics you can get a compile error at one point and not know that the problem actually stems from the fact that some class is not inherited somewhere else and you can get errors that make sense if you add constraints in the right areas.
Does that make sense? Am I on the right track?
I don't think that's the point of constraints, (but I may be wrong).
As I understand it, constraints don't have much to do with inheritance, per se. What you're really doing is putting constraints on the type that may be used if you are using (instantiating) a class that has type arguments.
Classes with type arguments are like Mad-Libs, and constraints are like the instructions that appear under the blanks:
"Bob like to ______ with his friends every night." (that's a madlib)
"Bob likes to _(verb)___ with his friends every night" (a madlib with instructions).
Check this:
//class with type arguments
public class MadLib<W> {
public void addWord(W word) {
System.Console.WriteLine("bob likes to " + word + " with his friends");
}
}
//class with type arguments and contraints (note i'm not inheriting nothin)
public class MadLib<W> where W:Verb{
public void addWord(W word) {
System.Console.WriteLine("bob likes to " + word + " with his friends");
}
}
Not exactly. Constraints are used to specify what behaviors and/or types a generic parameter can exhibit.
For example, if you declare a class:
class GenericDisposableHandler<T>
{
public void DoOperationOnT(T someVariable)
{
// can't really do much with T since its just an object type
}
}
and know for a fact that the generic parameter T should always be something that implements IDisposable, you would do:
class GenericDisposableHandler<T> where T : IDiposable
{
public void DoOperationOnT(T someVariable)
{
// Now you can treat T as IDisposable
someVariable.Dispose();
}
}
There are many other constraint types you can use.
Not really. Constraints are only applicable when you are defining a Generic class templare, (not when you inherit from a class).
When you define a generic, you are saying that this is a "template" or pattern, for some as yet undefined/unknown class with an as yet unknown Type, T, that will be created somewhere else based on this pattern and with an explicitly provided Type T. The constraint limits WHICH Types T can be used in the other place where you actually create the real type from the template/pattern
as in
//Define the generic here, with arbitrary type T
public class MyClass<T> where T: SomeOtherClass
{
// template/pattern methods, proerpties, fields, etc.
}
Create actual class here with explicitly provided Type "DerivedClass"
public MyClass<DerivedClass> myC = new MyClass<DerivedClass> ();
which will succeed if and only if DerivedClass inherits from SomeOtherClass
You can only inherit from one class, however you can implement several interfaces. The inheritance means that your class gets (inherits) whatever properties and methods that the base class specifies. As long as they're not marked as private, the inheriting class can call those methods as it's own.