0
votes

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.

3
It looks like you have more than one question here. For your first question, about what where T : class means, it's well answered in the MSDN documentation.Daniel Pryden
Your problem isn't because of the generic constraint, but because you neither close the generic nor provide the generic parameter in your new class. How would the compiler know the type of TEntity when you use Student in your code given what you've defined?Preston Guillot
@DanielPryden Thanks for the link...this will allow me to at least understand what I am looking for. Thanks for your answer.Francis Rodgers
@PrestonGuillot Given I don't understand generic constraints and until now did not even know they were called this (hence the question) I cant answer your query. But now that I know what to google I can learn more. Thanks for your answer.Francis Rodgers
I don't know why people vote a question down without providing a reason. Doesn't make sense to me. If they provided a reason, I could edit and improve the question. How can a question be bad on a Q&A site if it meets the various criteria for the site (if it doesn't, then explain why so I can edit). We all have to start somewhere.Francis Rodgers

3 Answers

2
votes

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 : classTEntity needs to be a reference type (i.e. created with class Something)
  • where TEntity : structTEntity 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.

1
votes
  1. 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.

  2. 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.

  3. 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.

1
votes

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.