What is the goal of Where in c#? - c#

i have this code:
Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelInteres;
i dont understand the goal of where, what is the goal?,
can someone explain to me what it is for, Is it mandatory to use the reserved word WHERE?

It is not mandatory at all. You would use where when you want to apply a constraint on the types of your generics.
Some examples:
class MyGeneric<T> where T : class {...}
T here can only be a class (no structs, like int, byte etc.), this makes it possible to handle better nullable types, for example.
class MyGeneric<T> where T : notnull {...}
T can be struct or class, but will never be null.
class MyGeneric<T> where T : new() {...}
T is a class that can be instantiated with an empty constructor. Useful if you want to have generic fabrics.
interface Animal { public int nrPaws {get;} }
class MyGeneric<T> where T : Animal {...}
T must implement the interface Animal. In this way you can control the methods you can call from MyGeneric.
where is generally very handy when you want these kind of checks to be done at compile-time rather that throwing error during run-time.

it constrains what types can be used for TViewModel

Related

How to understand recursive generic type constraint in Unity C#?

While I understand generic types <T> and where clause for constraint, I was confused about the following code from Unity Tower Defense Template:
public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
What's the purpose of restricting the type to be itself?
It prevents you from doing this:
public class A
{
}
public class B : Singleton<A>
{
}
You will get a compile error. Due to the type constraint, you must write:
public class A : Singleton<A>
{
}
Off the top of my head, one possible benefit of this is allowing methods to return the specific type. This is done by fluent style methods. Another example, obviously not applicable to the example you posted, is a Copy() method that returns a copy of the object as the derived type rather than as its base type. The method signatures of the Singleton< T> class you posted likely show where it uses the T parameter and likely hint at the reason why it uses this pattern.

C# Type Erasure Issues

Putting together a state machine in C#. I have an interface and abstract implementing class as:
public interface IState<SD> where SD : IStateData {
T EnterState<T>(InputData inputData, SD movementData) where T : IState<SD>;
}
public abstract class AMovementState : IState<MovementData> {
public abstract AMovementState EnterState<AMovementState>(InputData inputData, MovementData movementData);
}
MovementData implements IStateData so this seems like it should work fine. However I'm getting the compile error:
Error CS0425: The constraints for type parameter AMovementState' of methodAMovementState.EnterState(InputData, MovementData)' must match the constraints for type parameter T' of interface methodIState.EnterState(InputData, MovementData)'. Consider using an explicit interface implementation instead (CS0425) (Assembly-CSharp)
I think that this is an issue with type erasure but I'm not 100%. Do I need to rework my approach or am I missing something stupid? Coming from mostly a Java background.
I think that this is an issue with type erasure
C# does not have type erasure. C# has actual generic types deeply baked into the runtime.
To start with, you have made a common error; you did this:
class C {
C M<C>() { ... }
Oh the pain. This is so hard to read. The C in the method is the C declared by the method, not the C declared by the class. You did the same thing:
public abstract class AMovementState : IState<MovementData> {
public abstract AMovementState EnterState<AMovementState>(
InputData inputData, MovementData movementData);
}
Same thing here. You have declared two things, both called AMovementState, one a class type and one a type parameter. Please don't do that. It is incredibly misleading for the reader of the code.
Second, once you solve that problem: C# requires that a generic method which implements an interface method match exactly the constraints of that interface method.
Now, you may note that in this particular case, there is no logical requirement that the implementing method have the constraint. The type system could have been designed so that in this case, calling via the class gives a smaller constraint and calling via the interface gives a larger constraint, and that would be type safe.
But C# was not designed that way; it was designed so that constraints are required to match, even in cases where that is not strictly speaking necessary.
So, you have two choices:
Add the constraint to the abstract method, or
Do what the error message says. Create an explicit interface method that calls the class method.
That is either:
public abstract class AMovementState : IState<MovementData> {
public abstract M EnterState<M>
(InputData inputData, MovementData movementData)
where M : IState<MovementData>;
}
or
public abstract class AMovementState : IState<MovementData> {
public abstract M EnterState<M>
(InputData inputData, MovementData movementData);
M IState<MovementData>.EnterState<M>
(InputData inputData, MovementData movementData)
{
this.EnterState<M>(inputData, movementData);
}
}
Ironically, C# does not allow the constraints to be repeated on the explicit interface method; it infers them automatically. I've always thought of that as one of the oddest features of C#.
More generally: you may be suffering from Genericity Happiness Disease, that is the desire to make things generic even though it is unnecessary and hard to understand. Ask yourself whether a thing actually needs to be generic. Generics can be very difficult to reason about; maybe there is a simpler abstraction you can use.
Your class does not implement the interface, instead only one specific case.
You need to replicate the method generically:
public abstract class AMovementState : IState<MovementData> {
public abstract T EnterState<T>(InputData inputData, MovementData movementData) where T : IState<MovementData>;
}
The reason is simple: if some code holds a reference to a IState<MovementData>, they will call the method EnterState generically, therefore the implementation must also be generic.

C# interface inheritance: What does this code actually mean?

I was playing around with the following quick tutorial to add a repo layer to my MVC4 app. Well I got everything going good eventually. Now I am trying to add a "domain / business" layer.
I am getting errors when I try but they are not the problem I want to ask. Esentially. What I need to know is what does the following code actually mean:
public class HeadRepo<TEntity> : IHeadRepository<TEntity> where TEntity : class
Specifically I am talking about the fact that I have declared an interface (I know what interfaces are and how they work) so here is the interface declaration:
public interface IHeadRepository<TEntity>
I am assuming that -TEntity- is a generic type and could even be called -XYZAnything- but the standard convention is -TWhatever-. The T prefix being important, perhaps I am wrong, if so please correct me.
When I implement this interface using the first line above. What is actually happening? Specifically what does the
where TEntity : class
actually do for me. This is the important part of the question as this is the part I don't understand and would like to know what phrases to google to learn more about it (some links would be cool).
Finally, I am trying to inherit from another class. I know the rules of inheritance fairly well. I can only inherit from a single class, but multiple interfaces etc. So when I add the following code:
public partial class Student : Model.Student, IHeadRepository<TEntity> where TEntity : class
and also this variant
public partial class Student : IHeadRepository<TEntity> where TEntity : class
Things should work, I am inheriting from the Model class auto generated by EF so I can extend it by adding properties and methods. Occasionally I am told that a property in the base class does not exist (I know exists in the base class and is public as it is EF auto generated, and I checked). So don't know why it does this, but more specifically I get this error on both attempts:
Constraints are not allowed on non-generic declarations
I am assuming this has something to do with the where TEntity : class bit (mostly because this is highlighted with a red underline). hence the question.
Any help would be much appreciated.
I am assuming that TEntity is a generic type and could even be called XYZAnything but the standard convention is TWhatever. The T prefix being important
That’s correct. IHeadRepository<TEntity> is a generic interface with the generic type parameter TEntity which is just a name you can choose freely to reference the concrete type. The prefix T is just a convention which you should also follow.
where TEntity : class is a constraint on the generic type parameter TEntity and essentially means that TEntity should be a reference type. The general syntax is TEntity : SomeType which means that TEntity needs to be a subtype of SomeType. There are three special cases:
where TEntity : class – TEntity needs to be a reference type (i.e. created with class Something)
where TEntity : struct – TEntity needs to be a value type (i.e. created with struct Something)
where TEntity : new() – TEntity needs to have a default constructor, so you can use new TEntity() to create an object of that type.
class Student : Model.Student, IHeadRepository<TEntity> where TEntity : class
The generic type constrait always belongs to the type definition, so in your case, the where TEntity : class belongs to the definition of class Student. But since Student is not a generic type, you cannot have a generic type constraint.
Instead, you want Student to implement the generic type IHeadRepository<TEntity> (which has that constraint), so you will have to figure out what generic type you want to insert in that case:
class Student : Model.Student, IHeadRepository<SomeFoo>
{ }
In that case SomeFoo is required to follow the constraint of TEntity, i.e. SomeFoo needs to be a reference type. But what you want to insert there depends on what the interface actually means and how Student is supposed to implement it.
Prefix T is not important, but as you pointed out, it is a convention generally followed. You may note that one may have generic classes with <T,U>, or <TKey,TValue>.. just depends on what makes most sense in the context to you.
where TEntity : class This line tells the compiler, that you expect the generic type <TEntity> to be only reference types. And not value types. For example, if you said `HeadRepo, compiler will not allow it.
Typically when you want to add functionality to EF generated entity classes, you do not extend them (you could, in certain scenarios), but the classes generated by EF framework are partial classes.. Hence you could just declare your models partial class in another file, where you could add additional properties and methods etc.. This way EF will recognize your model class vs it not having any awareness of your new derived class.
The problem with the code public partial class Student : Model.Student, IHeadRepository<TEntity> where TEntity : class, is that while you are declaring a concrete class student, you are implementing a Generic Interface on it.. That doesn't make sense, because a concrete class must be concrete, and on contrary, you are making it implement a Generic interface, without specifying concrete type for TEntity. Like I said, extending Model.Student is not the right approach here..
Do not declare a new Student class.. You want to create a partial class for the same same Student class, as defined in your Model namespace.
Constraints
where TEntity : class
means that TEntity has to be a class. Otherwise it might be a struct or something else.
Inheritance with constraints
public partial class Student : IHeadRepository<TEntity> where TEntity : class
If you want to use constraints here you have to do like
public partial class Student<TEntity> : IHeadRepository<TEntity> where TEntity : class
Otherwise you have to use a concrete class without any constraints like
public partial class Student : IHeadRepository<YOURCLASS>
Of course YOURCLASS has to meet the constraint and therefore must be a class.

Class constraint must come before any other constraints

I am attempting to create the following class name signature:
public class MyClass<T> where T : struct, MyBase
(I am using struct to constrain to Enums)
I am getting error
The class type constraint 'MyBase' must come before any other constraints
I understand the message, however, rearranging the code I cannot get past that or some other syntax error. How can I fix that line if at all?
If I have to, I will remove struct.
Thank you
Constraints are "and-ed" together; all the constraints must be satisfied.
Under what circumstances can T be both a non-nullable value type and also be implicitly convertible to the class MyBase via identity, boxing or reference conversion?
There are no such circumstances, so there is no possible type argument that will satisfy T's constraints. Rather than letting you define a set of constraints that cannot be met, the compiler simply disallows it. You cannot state that you require both the struct constraint and a class type constraint.
I am using struct to constrain to Enums
That illustrates my point. Since there are no enums that inherit from MyBase, the constraint could not possibly be met.
Can you describe for me what you thought this meant? For example, did you think that it meant "any non-nullable value type or any type that is convertible to MyBase"? I am interested to learn why people believe false things about C# so that I can try to improve it.
UPDATE: Ah, I see -- MyBase is intended to be the base class of MyClass<T>, not the base class of T. In C#, it goes:
class [class name] < [generic type parameters] >
: [base classes and interfaces]
where [type parameter] : [constraints]
You have to put the base classes and interfaces before the constraints, otherwise the compiler thinks that they are the constraints.
Did you mean class MyClass<T> : MyBase where T : struct?
You're defining <T> as two different types.
struct is a value type where as MyBase is a class referring to a reference type.
It's not something that is interchangeable.
In this case it would be either:
public class MyClass<T> where T : struct
or
public class MyClass<T> where T : MyBase
Here is so more information regarding generics and how to use them.
If T must be a struct, it can't inherit from any other type... Value types don't support inheritance.
Not 100% sure on this, but a quick check of MSDN comes up with this where (generic type constraint) (C# Reference):
public class MyClass<T, U> where T : MyBase where U : struct
Not sure that's what you're looking for though.

C#: Add conditional generic method (different generic restriction) within generic class

I'm trying to add another restriction on a method within a generic class. Is this possible?
Pseudocode:
public class MyBaseClass<T> where T: class
{
public IQueryable<T> ShowThisMethod where T: class, IMyInterface
{
// stuff.
}
}
ShowThisMethod should only be available when T is IMyInterface. Also IMyInterface should then give information back (about T) so that I can access properties defined in IMyInterface inside of the method.
Help :)
By the way, this compiles (and seems "almost right"):
public class MyBaseClass<T> where T: class
{
public IQueryable<T> ShowThisMethod<T>() where T: class, IMyInterface
{
String X = T.MyInterfaceStringProperty;
}
}
More Information about my goal:
I'm using a generic base class to access a common property (DateTime "Time" property on LINQ object Dinner which is also on Lunch).
Both objects are implementing ITimeable which exposes the DateTime property.
In my base class I'd like to have a method Select() which works on IQueryable&ltT> and can automatically filter based on the Time property. Because I'm working off the generic T, the time property is not visible to the base class, unless I tell it that T is implementing ITimeable.
I do want the same base class to work for other non-ITimeable objects too, that's why I need the interface restriction on the Select method, and I also need it in order to access the Time property using generics.
Hope that clears the goal :)
P.S. My main concern is not visibility of the method in IntelliSense etc.. I'd just like to keep my base class working, while being able to access an interface-specified property through generics in it.
It depends on what you want.
Since the class is compiled once, and the magic with generics also relies on the runtime, there's no way to make a class that has some methods in some cases, and other methods in other cases. Either the methods are there, or they aren't.
So basically, there's no way to declare MyBaseClass so that the following happens:
MyBaseClass<Int32> bc;
bc. <-- intellisense does not show ShowThisMethod here
MyBaseClass<SomeTypeImplementingIMyInterface> bc2;
bc2. <-- intellisense DOES show ShowThisMethod here
... that is... by itself.
You can "trick" the compiler and intellisense into giving you what you're asking for, but know that this gives you other limitations and challenges that might need to be solved.
Basically, by adding an extension method to a static class declared alongside MyBaseClass, you can make intellisense, and the compiler, behave as if the method is only present for MyBaseClass when T has some specific rules, as you're asking for.
However, since the method in question will be a static method, defined outside of MyBaseClass, there's limits to how much of the internals of MyBaseClass you can access, and you can't access the method inside MyBaseClass, so it depends on what you want to accomplish and whether you can live with the limitations or not.
Anyway, here's the extension method. Note that you remove it completely from MyBaseClass at the same time:
public static class MyBaseClassExtensions
{
public static IQueryable<T> ShowThisMethod<T>(this MyBaseClass<T> mbc)
where T: class, IMyInterface
{
...
}
}
Also note that ShowThisMethod is redefining T in the context of ShowThisMethod. It is not the same T as defined by the class.
Specifying a different Type parameter where the new one inherits from the one defined by the class would be the best approach, though that ends up requring the caller to have to specify the generic Type twice.
No, it's not possible. Constraints are defined when they are declared. In this case, the method is not generic, the class is (it's a non-generic method of a generic class). So the constraints can be only declared on the class itself.
Will this do what you want? The method will be visible to anyone, but not necessarily useable...
public class MyBaseClass<T> where T: class
{
public IQueryable<R> ShowThisMethod() where R: T, IMyInterface
{
Debug.Assert(typeof(R) == typeof(T));
// stuff.
}
}
You could define another class that inherits MyBaseClass and redefine the constraint :
public MyOtherClass<T> : MyBaseClass<T> where T : class, IMyInterface
{
public IQueryable<T> ShowThisMethod()
{
// stuff.
}
}

Categories