I'm trying to create a generic LINQ-TO-SQL repository based on this post which basically lets you define a generic base repository class, then you can define all of your actual repository classes by deriving from the generic base.
I want the option of using a repository with or without passing in the data context, so I decided to create two constructors in the generic base class:
public abstract class GenericRepository<T, C>
where T : class
where C : System.Data.Linq.DataContext, new()
{
public C _db;
public GenericRepository()
{
_db = new C();
}
public GenericRepository(C db)
{
_db = db;
}
public IQueryable<T> FindAll()
... and other repository functions
}
To use it, I would derrive my actual repository class:
public class TeamRepository : GenericRepository<Team, AppDataContext> { }
Now, if I try to use this with a parameter:
AppDataContext db = new AppDataContext();
TeamRepository repos=new TeamRepository(db);
I get the error:
'App.Models.TeamRepository' does not contain a constructor that takes 1 arguments
So, it looks like you cant inherit constructors in C#, so, how would you code this so I can call: TeamRepository() or TeamRepository(db)
Derived classes do not automatically inherit any base class's constructors, you need to explicitly define them.
public class TeamRepository : GenericRepository<Team, AppDataContext>
{
public TeamRepository() : base() { }
public TeamRepository(AppDataContext db) : base(db) { }
}
Do note however that if the base class defines (implicitly or explicitly) an accessible default constructor, constructors of the derived class will implicitly invoke it unless the constructor is invoked explicitly.
You're correct, constructors in C# are not bubbled up into subclasses. You'll have to declare them yourself. In your example, you'll need to surface two constructors for each of your repositories.
Related
I have a set of classes that inherit from a base...
public abstract class BaseClass
{
public BaseClass()
{
// ...
}
}
public abstract class BaseMessageClass : BaseClass
{
// ...
}
public SpecificMessageClass : BaseMessageClass
{
// ...
}
Instantiating an object like this works:
SpecificMessageClass myMessage = new SpecificMessageClass();
However, I need to change all constructors to have an optional string parameter, like this:
public abstract class BaseClass
{
public BaseClass(string optParam="whatever")
{
// ...
}
}
Now, when I try and instantiate the object with the optional argument:
SpecificMessageClass myMessage = new SpecificMessageClass("coolstring");
I get the error:
'SpecificMessageClass' does not contain a constructor that takes 1 arguments"
Is there ANY way to do this without explicitly declaring the constructors in each level of inherited class?
No.
But given that you want to inherit, I'm guessing you want the same logic to apply at all levels on some inherited field or property. If so, the closest you can get is to add a factory method like a Create<T>(string optParam="whatever") on the base class like the following:
public class BaseClass
{
public static T Create<T>(string optParam="whatever") where T : BaseClass
{
var t = new T(); //which invokes the paramterless constructor
((BaseClass)t).SomePropertyOrFieldInheritedFromTheBaseClass = optParam; //and then modifies the object however your BaseClass constructor was going to.
return t;
}
}
That would allow all implementers of the class to implement the BaseClass and get the same effect as having the optional parameter constructor.
By the way, I didn't test the above code, so you might need to tweak it slightly. But hopefully it gives the idea.
I think that's probably the closest you can get.
Constructors are special methods. If your class specifies no constructors, it will have a no-args constructor that inherits from the parent's no-args constructor. As soon as you specify a single constructor, you do not automatically get any of the parent's constructors for free. You must declare each different constructor you need.
I am having a C# abstract class which have some methods to be implemented by its children.
Though it is so, the initialization values for those children consist of two parts: one which is the same as the parent, and another one which is unique to the children.
public abstract class parentClass {
public abstract bool IsInputValid(string input); //children must implement this
public parentClass () {
//Some shared initialization
}
}
If the class is not abstract we could do something like this to implement that
public class parentClass {
public parentClass (string input) {
//Some shared initialization
}
}
public class childClass : parentClass {
public childClass (string input) : base (input) {
//Some unique initialization
}
}
But that cannot be done using abstract class and some more, the method not need not to be implemented (since it is not abstract).
So I am in a dilemma here. On one hand, I want to have some base initialization called and on the other, I also want to have some methods enforced.
So my question is, how do we normally implement such case? On one hand it is enforcing some base initialization, and on another some methods.
Note: I am new to abstract class so I would be glad to receive any inputs regarding it.
Where do I declare wrongly (if any)? If we cannot do so, is there a way to get around to produce the same result (that is, to enforce the child class to use certain signature for constructor)?
There should be no need to enforce this. You say that the base class has some common initialization and the child classes have their own specialized initialization as well.
This is enforced already, if you have this:
public abstract class Base
{
protected Base(int value) { ... }
}
Then you have a couple of guarantees:
Nobody can construct an object of the type Base since it is abstract
Nobody can construct an object that inherits from Base without indirectly calling the only existing constructor of Base, that takes an int value parameter.
The last part there is important.
A child class can deal with this type of base constructor in at least three ways:
It can provide a constructor that looks identical save the name of it, just passing the value down to the base constructor:
public class Child : Base
{
public Child(int value) : base(value) { ... }
}
It can provide a constructor that has this parameter but has additional parameters to the child class constructor as well:
public class Child : Base
{
public Child(int value, string other) : base(value) { ... }
}
It can provide a constructor that doesn't have the parameter to the base class, but manages to compute this parameter:
public class Child : Base
{
public Child(string other) : base(other.Length) { ... }
}
The last part also handles the case where the child constructor has no parameters at all:
public class Child : Base
{
public Child() : base(new Random().Next(100)) { ... }
}
Regardless of which approach you use, it is impossible to call the base class constructor without passing a value for that parameter, hence you have enforce the following:
Child classes has to be aware of the base class constructor and its parameter
But you cannot, and should not, try to enforce the presence of a particular constructor with a specific signature.
Now, having said that, what if you want to create some sort of common way to construct two distinct child classes, that has such different constructors, in such a way that code that uses them doesn't need to know the specifics of either constructor?
Enter the factory pattern (Wikipedia):
In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.
(quoted text copied from entry paragraph in the Wikipedia-article)
Here's a way to abstract away the presence and knowledge of such different constructors and child classes:
void Main()
{
Test(new Child1Factory());
Test(new Child2Factory());
}
public void Test(IBaseFactory baseFactory)
{
Console.WriteLine("In Test(...");
var b = baseFactory.Create();
}
public class Base
{
public Base(int value)
{
Console.WriteLine($"Base.ctor({value})");
}
}
public interface IBaseFactory
{
Base Create();
}
public class Child1 : Base
{
public Child1(int value) : base(value)
{
Console.WriteLine($"Child1.ctor({value})");
}
}
public class Child1Factory : IBaseFactory
{
public Base Create() => new Child1(42);
}
public class Child2 : Base
{
public Child2(string name) : base(name.Length)
{
Console.WriteLine($"Child2.ctor({name})");
}
}
public class Child2Factory : IBaseFactory
{
public Base Create() => new Child2("Meaning of life");
}
Pay special attention to the Test(...) method, as this has no knowledge of which Base child it will get, nor how to construct such an object. If you later on add new child types from Base, you will have to provide new factories as well but existing code that uses these factories should not need to be changed.
If you want a simpler factory pattern all you have to do is replace the interface and factory classes with a delegate:
void Main()
{
Test(() => new Child1(42));
Test(() => new Child2("Meaning of life"));
}
public void Test(Func<Base> baseFactory)
{
Console.WriteLine("In Test(...");
var b = baseFactory();
}
Final note here. Since the factory pattern means you will have to create a different type that does the actual construction of the object you can enforce the signature of that other type, either by
Adding parameters to the Create method on the factory interface
Specifying a delegate that has parameters to the factory delegate
This means you can enforce the signature of "the creation process". Still, you cannot enforce the presence or signature of a particular constructor, but the constructor is just a means to an end, create an object, and with the factory pattern you can actually formalize this pattern in your code and thus you should get what you want.
You cannot enforce the signature or even existence of constructors of your derived classes. (or any class for that matter)
I'm afraid that's the end of the story. You aren't doing anything wrong, it's just not possible.
Since you can't override constructors in c#, you cannot enforce the existence of a certain constructor in the derived class .
This means:
a constructor cannot be abstract, virtual etc
constructors aren't polymorphically
You cannot have an abstract constructor, but neither is there any need to.
All you need to do is remove the "abstract" keyword from your parentClass and you should be good to go.
I am dealing with an issue that I have no idea how to work around. I am using ASP.NET Boilerplate and have been following this guide and its source to the T: Using-AngularJs-ASP-NET-MVC-Web-API-and-EntityFram
I have a problem building my first repository. It's giving me the following error: Error 1
'Test.EntityFramework.Repositories.TestRepositoryBase'
does not contain a constructor that takes 0 arguments
This is the Repository:
public class UserInfoRepository : TestRepositoryBase<UserInfo, Guid>, IUserInfoRepository
{
}
While the base:
public abstract class TestRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<TestDbContext, TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
protected TestRepositoryBase(IDbContextProvider<TestDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
//add common methods for all repositories
}
Any suggestions?
The base classes always force their signature of constructors to the derived classes. As you know the base class constructor should be called on derived class instance creation. If you define default(parameterless) constructor and try to new it there is only one constructor in base class which takes 1 argument and it should be called, but there is no argument to pass in. The base class non-default constructor should be called explicitly on derived class constructor implementation to provide ability to pass argument in. To fix the situation you should explicitly call base class constructor and pass argument in.
public UserInfoRepository (IDbContextProvider<TestDbContext> dbContextProvider)
: base(dbContextProvider)
{}
I have a parent Class
public class GenericRepository<TEntity> where TEntity : class
{
//Implementation
}
And I want to inherit from this class, but I can't seem to get it right,here are my attempts
public class CustomerRepository<Customer> : GenericRepository<Customer>
{
//implementation
}
Or this,
public class CustomerRepository<T> : GenericRepository<T> where T : new Customer()
{
}
Or this one
public class CustomerRepository<T> : GenericRepository<CustomerRepository<T>> where T : CustomerRepository<T>
{
}
No matter what I do, I get this error. Please show me how I can inherit from this class, classes share the same Namespace
Error 'GenericRepository' does not contain a constructor that takes 0 arguments CustomerRepository.cs
It sounds like you want a non-generic class inheriting from a generic one, like this:
public class CustomerRepository : GenericRepository<Customer>
{
}
If you want this to be a generic class that narrows the type of the generic parameter (only allows Customer or a derived type):
public class CustomerRepository<T> : GenericRepository<T>
where T : Customer
{
}
Regarding your compile-time error:
Error 'GenericRepository<Customer>' does not contain a constructor that takes 0 arguments
This means exactly what it says. You have not defined a constructor in your derived class, which means that a constructor is implicitly generated, as though you had typed this:
public CustomerRepository() : base() { }
However, the base class (GenericRepository<Customer>) does not have a constructor that takes no arguments. You need to explicitly declare a constructor in the derived class CustomerRepository and then explicitly call a constructor on the base class.
You don't need to repeat the type parameter in the deriving class, so:
public class CustomerRepository : GenericRepository<Customer>
{
//implementation
}
Is what you need.
It seems that your base class has no constructor without parameters, if so the derived class must declare a.constructor and call the base class constructor with parameter.
class MyBase { public MyBase(object art) { } }
class Derived : MyBase {
public Derived() : base(null) { }
}
In this example if you remove the ctor from Derived you get the same error.
Use can write as:
public class CustomerRepository : GenericRepository<Customer>
{
//implementation
}
Here is what I'm trying to do, not even sure if possible..
I'm creating BaseViewModel<T> and I want it to accept types inherited from Entity
Consider this code:
public abstract class BaseViewModel<T> : NotificationObject, INavigationAware
{
public T MyEntity;
public SomeMethod()
{
MyEntity.SomeEntityProperty = SomeValue;
}
}
So, I want to say that my T inherited from Entity and therefore I KNOW that it will have SomeEntityProperty.
Is this possible?
Salvatore's answer is totally correct, I just wanted to describe the concept a little better.
What you need is a "generic type constraint"; to specify that the type used as T must conform to certain behaviors (such as being derived from an object or interface more derived than Object), thus increasing what you are allowed to do with that object without further casting (which is generally to be avoided in generics).
As Salvatore's answer shows, GTCs are defined using the "where" keyword:
public abstract class BaseViewModel<T> :
NotificationObject,
INavigationAware
where T : Entity;
{
...
This GTC basically states that any T must derive (however remotely) from Entity. This allows you to treat T as if it were an Entity (except for instantiation of new Ts; that requires an additional GTC), regardless of how more or less derived the actual generic parameter type is from Entity. You can call any method that appears on Entity, and get/set any field or property.
You can also specify that:
The type must be a class (where T:class), or alternately must be a ValueType (where T:struct). This either permits or prevents comparison and assignment of a T instance to null, which also allows or prevents use of the null-coalescing operator ??.
The type must have a parameterless constructor (where T:new()). This allows instantiations of Ts using the new keyword, by ensuring at compile-time that all types used as Ts have a constructor that takes no parameters.
public abstract class BaseViewModel<T> :
NotificationObject,
INavigationAware
where T : Entity
{
public T MyEntity;
public SomeMethod()
{
MyEntity.SomeEntityProperty = SomeValue;
}
}
Just use the where keyword:
public abstract class BaseViewModel<T> : NotificationObject, INavigationAware
where T:Entity
{
...
Try using the where constraint:
public abstract class BaseViewModel<T> : NotificationObject, INavigationAware
where T : Entity
{
public T MyEntity;
public SomeMethod()
{
MyEntity.SomeEntityProperty = SomeValue;
}
}