it's my first question, excuse my incompetence,
I am trying to declare an object that is created from the inheritance of the same class but it tells me that I cannot cast the object being inherited
abstract class BaseEntity{...}
abstract class BaseController<T> where T : Model.BaseEntity{...}
class DummyEntity : BaseEntity {...}
class DummyController : BaseController<DummyEntity> {...}
When I want to create an object, it indicates that it cannot be implicitly converted.
BaseController<BaseEntity> a = new DummyController();
You cannot do that. This has something to do with covariance.
Imagine the BaseController<T> has a method Add(T entity).
Now you create an instance of DummyController. You can call Add(CowEntity entity) on this instance because DummyController inherits BaseController<CowEntity> so T is CowEntity.
Now if you were able to assign this to BaseController<BaseEntity> you would suddenly be able to call Add(BaseEntity entity) (because T is now BaseEntity, not CowEntity anymore).
This means you could add an instance of ChickenEntity (which has nothing to do with CowEntity, it's just another derived class of BaseEntity) to that base-controller which is actually an instance of BaseController<CowEntity>. Now suddenly an instance of BaseController<CowEntity> contains a ChickenEntity. You see that this doesn't make sense.
To solve this you need to read about interfaces and covariance (and contravariance).
Hope this helps :)
Related
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.
Consider the following:
public class EntityBase<TEntity>
{
public virtual void DoSomethingWhereINeedToKnowAboutTheEntityType()
{
}
}
public class PersonEntity : EntityBase<PersonEntity>
{
public override void DoSomethingWhereINeedToKnowAboutTheEntityType()
{
}
}
I added this into code and ran it and it worked ok, but I'm surprised that I can inherit a class who's definition is based on the inheriting class.
When I tried it I was expecting either it not to compile, or to fail once actually called.
You can do something similar with an interface:
public interface IEntityBase<TEntity>
{}
public class PersonEntity : IEntityBase<PersonEntity>
{}
I've actually switched my code from the former to the later, using the interface, but I'm still curious why this works.
It works because there's no reason why it wouldn't work. EntityBase<PersonEntity> doesn't inherit from PersonEntity, it merely references the type. There's no technical problem with a base class knowing about its own derived class. This also works (even though this specific example is a bad idea):
public class A
{
public B AsB()
{
return this as B;
}
}
public class B : A
{
}
I'm surprised that I can inherit a class who's definition is based on the inheriting class.
Careful - what you're inheriting is a class whose definition involves an arbitrary Type, is all. All of these are legal:
class O : EntityBase<object>
class S : EntityBase<String>
class Q : EntityBase<Q>
All you've said in the definition of EntityBase is that TEntity should be a type - well, PersonEntity is a type, isn't it? So why shouldn't it be eligible to be a TEntity? No reason why not - so it works.
You might be concerned about the order of definitions, but remember that within the unit of compilation, everything gets defined 'at once' - there's no sense in which PersonEntity needs to be compiled 'before' anything else (including itself!) can refer to it. Indeed, you're even allowed
class A : EntityBase<B>
class B : EntityBase<A>
for which no conceivable 'order of compilation' could work, if such a thing were needed.
A very simple example is the generic interface IComparable<T>. Usually, you implement it like this:
class MyClass : IComparable<MyClass> {/*...*/}
This implementation of the generic template is just saying that MyClass objects can compare to other MyClass objects. As you can see, there is no problem with the mental model. I can very well understand the concept of a class whose objects can compare between them without knowing anything else about the class.
The main point here is that template parameters are just used by the generic class or interface, but they need not be related by inheritance at all. IComparable<MyClass> does not inherit from MyClass. So there is no circularity.
I have a base object abstract class and a base object collection class for some business objects to inherit from. I'm trying to figure out how to pass the base object type to the collection class (and other methods). I've been able to solve this by wrapping the class in an interface but i'm wondering if there is another way to do this or if using an interface is the best way. i think my question might make more sense from the code below.
i have a base class define -
public abstract class BaseObject<TYPE,KEY>:where TYPE:BaseObject<TYPE,KEY>, new()
public KEY ObjectId {get;protected set; }
i have a class that inherits from BaseObject
public class Customer : BaseObject<Customer,Guid>
My base collection class is -
public abstract class BaseObjectCollection<T> : List<T> where T: BaseObject, new()
I also have a few methods in other class that want to reference this baseclass -
public bool ValidateRule(BaseObject dataObject) {etc...}
If you use the base class in other classes that are not also generics, then I'm afraid that you're going to have to specify the type and key parameters for the object when you pass it to methods like ValidateRule.
In this design, an Interface implemented by the base object is probably the most appropriate solution. We use this pattern extensively in our code and it works quite well.
One other item you could explore is reducing the complexity of the base class slightly by moving the Key into the class as an overridable (or must override) property that defaults to a string or int or whatever may be appropriate. We found that this approach (we forced all collection keys to be strings) significantly reduced the class complexity.
I would like to pass a generic interface to a function:
private I<T> CreateStubRepository<T, I >()
where I : aGenericBaseClass
So i was wondering if generic interfaces implement a base class or specific interface?
I know by using reflection you can test if it is a generic class but I dont see that helping me
Well. What's the point of forcing the usage of any interface? I really do not get it (or your question).
You should more likely do something like this:
public interface IMyRepository<T>
{
}
public class Repository<T> : IMyRepository<T>
{
}
private IMyRepository<TEntity> CreateStubRepository<TEntity>()
{
return new Repository<TEntity>();
}
var repos = CreateStubRepository<User>();
Update
thanks for your answer but thats not what I am asking. What I want to know is does a class that implements a generic interface have a base class or does it inherit from an interface? I dont want to force any interface its more a question of is the object passed generic
Classes do not inherit interfaces. They implement them. The different is subtle but important.
A class can only inherit another class. This means that if you do not specify that a class inherits from another it will still inherit from object. And that wont change no matter how many interfaces a class implement.
class MyClass : ICoolInterface // inherits object
class MyList : ArrayList, ISomeInterface // inherits ArrayList
class MyGenericList<T> : IList<T> // inherits object.
Generic or non-generic classes can implement or inherit from generic or non-generic interfaces and classes. The only limitation is that the full type of any interface/class implemented/inherited from must be discernible given the full type of the class doing the implementing or inheriting. For example, a Foo<Bar> might inherit from FooBase and implement IDisposable; a FnordDuffleBag might inherit from DuffleBag<Fnord> and implement IReachInto<Fnord>.
Thanks for all the comments I think i was going in the wrong direction, What I was hoping for was that when I applied to a class the framework would know that it inherited from a base class or interface of say aGenericItemBaseClass before it constructed the class at runtime.
Yes I know that I can create a generic class with type parameters and use that but thats not what I was asking (although you may have got that impression from my posting).
At runtime I know that when using reflection I can determine if a class is generic by calling : IsGenericType which returns true if a type is generic.
So what I wanted to know which may have been explained poorly is, when using template types is there anyway to determine if that type is a generic type? It appears the answer is No the IL interperates the class as generic not the compiler.
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<T> 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.
}
}