How to Inherit from Generic Parent - c#

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
}

Related

Inherit Generic classes

I have a class like below. But I don't know how to inherit it in another class, I need to override a method in this class. I tried many ways but it seems that the parameters TUser and TKey are still in the wrong syntax. How to inherit similar classes?
public class AspNetIdentityUserService<TUser, TKey> : UserServiceBase
where TUser : class, Microsoft.AspNet.Identity.IUser<TKey>, new()
where TKey : IEquatable<TKey>
{
protected readonly Microsoft.AspNet.Identity.UserManager<TUser, TKey> userManager;
protected readonly Func<string, TKey> ConvertSubjectToKey;
public AspNetIdentityUserService(
Microsoft.AspNet.Identity.UserManager<TUser, TKey> userManager,
Func<string, TKey> parseSubject = null)
{
// initilaization
}
//More Methods
}
I tried inheriting like
public class EnforcingLocalSignup<TUser, TKey> :
AspNetIdentityUserService<TUser, TKey> where TUser : class,
Microsoft.AspNet.Identity.IUser<TKey>, new() where TKey : IEquatable<TKey> { }
but it fails with
Error CS7036 There is no argument given that corresponds to the required formal parameter 'userManager' of 'AspNetIdentityUserService<TUser, TKey>.AspNetIdentityUserService(UserManager<TUser, TKey>, Func<string, TKey>)'
Here's brain dead simple code that repros your error:
public class BaseClass
{
public BaseClass(string userManager)
{
UserManager = userManager;
}
public string UserManager { get; }
}
public class SubClass : BaseClass
{
}
Which results in this error (pointing to the public class SubClass : BaseClass line):
error CS7036: There is no argument given that corresponds to the required formal parameter 'userManager' of 'BaseClass.BaseClass(string)'
This happens because the base class has no default constructor, only the one that requires a userManager parameter.
That's the same error you are seeing. Note that it has nothing to do with the complicated generic nature of your classes, only with how the constructors are, um, constructed. Subclass, since it doesn't define a constructor, gets the default default constructor (i.e., one that just sets all properties to their default values).
If I add a default constructor:
public SubClass () { }
I get the same error, this time pointing to that line of code. However, if I create a constructor like that calls the one-and-only base class constructor:
public SubClass(string userManager) : base (userManager)
{
}
The error goes away.
When you define a class without defining any constructor, a parameterless constructor is implicitly defined.
Basically this:
public class MyClass { }
Actually is interpreted by the compiler like this:
public class MyClass : System.Object
{
public MyClass() : base() { }
}
This works because System.Object class has a parameterless constructor, that you can call via base().
When a class defines a constructor with parameters but not a parameterless constructor, the compiler won't generate a parameterless constructor, so this code:
public class BaseClass
{
public BaseClass(int parameter)
{
// ...
}
}
Actually is interpreted (and compiled) as:
public class BaseClass : System.Object
{
public BaseClass(int parameter) : base()
{
// ...
}
}
Now, if you inherit from a class that is missing a parameterless constructor without defining a constructor, like this:
public class MyClass : BaseClass { }
What the compiler "sees" is actually this:
public class MyClass : BaseClass
{
public MyClass() : base() { }
}
But BaseClass do not have a constructor that takes no parameters, hence the compilation error.
It's easily fixed by either define a parametered constructor in your derived class that matches the constructor of base class:
public class MyClass : BaseClass
{
public MyClass(int parameter) : base(parameter) { }
}
or a parameterless constructor that passes a default value to base constructor:
public class MyClass : BaseClass
{
public MyClass() : base(0) { }
}
depending on your design requirements.
Wrapping up and applying to your case, you can fix with:
public class EnforcingLocalSignup<TUser, TKey> : AspNetIdentityUserService<TUser, TKey>
where TUser : class, Microsoft.AspNet.Identity.IUser<TKey>, new()
where TKey : IEquatable<TKey>
{
public EnforcingLocalSignup(Microsoft.AspNet.Identity.UserManager<TUser, TKey> userManager,
Func<string, TKey> parseSubject = null)
{ }
}
When inheriting from, towards or between generic classes, you have 3 options for any of the generic parameters:
a) Expose them on the new class as well. Hand them through:
class MySpeciaList<T> : List<T>{
//You propably want to write something additional here
}
Do not that constraints on MySpeciaList<T> must be at least as restrictive as on the class you inherit from.
b) Hardcode the type. Basically you "de-generezie" the class
class FormList : List<Form> {
//You do not need to add anything here, but maybe want to
//We have to use that trick for XAML, as generics types are not really useable in XAML code
//Note that .NET does have a "Formlist" type, it is from the pre-generic days
}
c) you can of course add generic parameters, that only the new class can use. Indeed you propably do that impicitly:
class SomethingGeneric<T> : object {
//You most definitely should add something here. Ideally something using T
}
All of these can be combined. You can hand through, hardcode and add any number of generic placeholders. Do not that you propably want to use type aliases and var, to keep the code readable.

Method constraint must be super of class generic

How can I do the following?
I have a method which I need to say its generic type must be the super of the classes generic type.
Here is an example:
class Logger : ILogger, IStartable {}
///use
new FluentBuilder<Logger>().As<ILogger>().As<IStartable>();
This shows my intent, however does not work (as it is not syntactically incorrect):
public class FluentBuilder<TService> where TService : class
{
public FluentBuilder<TService> As<TContract>() where TService : TContract
{
return this;
}
}
This is not exactlywhat you want, but maybe a step in the correct direction. You can implement your As method as extension method:
public static class Ex
{
public static FluentBuilder<TService> As<TService, TContract>(this FluentBuilder<TService> that)
where TContract : class
where TService : class, TContract
{
return that;
}
}
The usage syntax is then:
new FluentBuilder<Logger>().As<Logger, ILogger>().As<Logger, IStartable>();

C#: force constructor inheritance

I've read a lot of questions of people asking how to have implicit ctor inheritance, so to not have to copy them around.
This question is totally the opposite: why C# is not forcing me to do it anymore? I want the derived classes to be forced to implement the base constructors...but it's not happening. What am I doing wrong?
Base class
public abstract class LogicalDevice
{
private LogicalDevice()
{
}
protected LogicalDevice(string id)
{
}
}
Intermediate derived class
public abstract class Device : LogicalDevice
{
public Device(string ID)
: base("ID")
{
}
public Device(ConfigurationData configuration)
: base(configuration["ID"])
{
}
}
Final derived class
internal class CoffeMachineDevice : Device
{
public CoffeMachineDevice (ConfigurationData configuration)
: base(configuration)
{
}
}
Why the class CoffeMachineDevice compiles?
C# requires that every constructor in derived class must call a constructor in the base class. But there is no requirement that is must call each constructor of the base class.
That's why CoffeMachineDevice compiles.

Why is my C# class telling me there's no constructor with zero arguments?

I have the following:
public class TestService : BaseService, IDisposable
{
public TestService(IRepositoryProvider repositoryProvider)
{
}
public IRepository<Exam> Exams { get { return GetStandardRepo<Exam>(); } }
}
and
public class BaseService : IDisposable
{
public BaseService(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
}
Can someone tell me why there's an error on the first class saying "Base Service does not take a constructor with zero arguments" ?
You need to call your base constructor:
public TestService(IRepositoryProvider repositoryProvider) : base(repositoryProvider)
{
}
You need to pass the IRepositoryProvider to the BaseService constructor by chaining it:
public class TestService : BaseService, IDisposable
{
public TestService(IRepositoryProvider repositoryProvider) :
base(repositoryProvider)
{
}
public IRepository<Exam> Exams { get { return GetStandardRepo<Exam>(); } }
}
Since you have not done so, it is interpreted as trying to initialize BaseService using a parameterless constructor, which does not exist.
You need to call the base constructor of BaseService. Change your implementation like this:
public class TestService : BaseService, IDisposable
{
public TestService(IRepositoryProvider repositoryProvider)
: base(repositoryProvider)
{
}
public IRepository<Exam> Exams { get { return GetStandardRepo<Exam>(); } }
}
The reason is that the base class does not contain a parameter less constructor i.e. a constructor which takes 0 arguments.
When the constructor of this derived class is called it will call the parameter less constructor of the base class as there is no explicit call to the constructor of the base class and since there is no parameter less constructor in the base class the above error occurs.
Because the constructor in TestService will try to call BaseService with no argument.
fix:
public TestService(IRepositoryProvider repositoryProvider): base(repositoryProvider){ }

Cannot use polymorphism because of generic base class

I create base generic class with no fields with just one method
public class Base<T> where T:class
{
public static T Create()
{
// create T somehow
}
}
public class Derived1 : Base<Derived1>
{
}
public class Derived2 : Base<Derived2>
{
}
public class Program
{
bool SomeFunction()
{
// Here I need reference to base class
Base baseref; // error here
switch(somecondition)
{
case 1:
baseref = Derived1.Create();
break;
case 2:
baseref = Derived1.Create();
break
}
// pass baseref somewhere
}
}
An obvious option would be converting base class to interface, but this is not possible because interface cannot contain static methods.
I think I need some intermediate base class. Please suggest
You must remove the generic parameter from the Base class, you can move it to just the Create method:
public class Base
{
public static T Create<T>() where T : class
{
return Activator.CreateInstance<T>();
}
}
public class Derived1 : Base
{
}
public class Derived2 : Base
{
}
Preliminary Assessment
With this statement,
public class Derived1 : Base<Derived1> {
you're using Derived1 in two different ways according to the base class.
You're effectively telling the C# compiler that Derived1 both:
inherits Base
and Base uses instances of Derived1 through non-inheritance means.
This is not wrong (if that's what you really want), but it's unusual for most programming scenarios; you normally choose one or the other. However the benefit of your logic is: not only do you have an implicit instance of Derived1 through inheritance (same for any other derived class), but the base class can also handle other external instances of that same derived type through the type parameter <T>
One problem I see in the Base class is it turns into a kind of circular scenario when using the factory method as intended, because, to support all derived classes it would need to support something like class Base<T> where T:Base<T>. That's next to impossible to declare because you would have to say in a circular fashion: Base<Base<Base<!!!>>> baseref = null; where !!! represents an infinite number of the same.
One Solution...
One possible (and strong solution) is to move the Type parameter from the class to the factory Create method and restrict its usage to the Base class type like so:
using System;
public abstract class Base
{
public static T Create<T>() where T : Base
{
return Activator.CreateInstance<T>();
}
}
Note: I have made the base class abstract which restricts instantiation to the derived types; however you can still use base class references (see switch statement usage below).
These derived classes still inherit from base.
public class Derived1 : Base
{
}
public class Derived2 : Base
{
}
Your factory method is restricted to create only instances of derived types. The logic has been swapped around so the derived type is given to the factory method instead of the factory method being called on it.
public class Program
{
bool SomeFunction()
{
Base baseref = null;
switch(DateTime.Now.Second)
{
case 1:
baseref = Base.Create<Derived1>(); // OK
break;
case 2:
baseref = Base.Create<Derived2>(); //OK
break;
case 60:
baseref = Base.Create<string>(); //COMPILE ERR - good because string is not a derived class
break;
}
// pass baseref somewhere
}
}
public abstract class Base
{
}
public class Base<T> : Base where T : class
{
public static T Create()
{
// create T somehow
}
}
public class Derived1 : Base<Derived1> // also inherits non-generic Base type
{
}
public class Derived2 : Base<Derived2> // also inherits non-generic Base type
{
}
How about creating an interface and having the abstract class implement the interface?

Categories

Resources