Inherit Generic classes - c#

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.

Related

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>();

Ensure parameter on generic method is base of paramater in the same class

I have a generic class defined as follows:
public abstract class BaseValidator<T> : IValidator<T> where T: IEntity
{
//some methods and parameters here
protected void Include<E>(IValidator<E> validator) where E : class , IEntity
{
if (typeof(E) != typeof(T).BaseType)
{
throw new ArgumentException($"Generic class Validator<T> must only Include Validators for base classes");
}
//Some business logic around connecting validators
}
}
The method Include is designed to take in a Validator parameter, it uses this to bind validators to each other, similar to a chain of responsibiity of validators. I currently have run time checking to ensure that E is a base class of T but I would like to move this to compile time checking.
I have attempted to add on a second where clause to the method Include as follows:
where T:E
However visual studio complains that the method Include does not define a Type parameter 'T'
If I do define a type parameter I get a message stating that the type parameter 'T' has the same name as the type parameter on the outer class.
How can I ensure that the generic type passed into my method is the base class that my T implements?
Edit 1:
public class BankAccountValidator : BaseValidator<BankAccount>
{
public BankAccountValidator(IValidator<OwnedProduct> validator)
{
Include(validator);
//Some logic here
}
}
In this case BankAccount implements OwnedProduct. So when a validate method is called on BankAccount it also calls validate on OwnedProduct.
I want to enforce that you cannot pass in to BankAccountValidator another BankAccountValidator or if I have a OwnedCredit type which BankAccount does not derive from that I cannot pass the OwnedCreditValidator in to the constructor.
There are a large number of validators and having it strongly typed like this would prevent me from running into runtime issues.
public abstract class BaseValidator<T, E> : IValidator<T>
where E: IEntity
where T: E
{
//some methods and parameters here
protected void Include(IValidator<E> validator)
{
//Some business logic around connecting validators
}
}
public class BankAccountValidator : BaseValidator<BankAccount, OwnedProduct>
{
public BankAccountValidator(IValidator<OwnedProduct> validator)
{
Include(validator);
//Some logic here
}
}
If OwnedProductValidator can validate himself, then:
public class OwnedProductValidator : IValidator<OwnedProduct>
{
// IValidator interface implementation
}
public class Program
{
public static void Main()
{
var ownedProductValidator = new OwnedProductValidator();
var bankAccountValidator = new BankAccountValidator(ownedProductValidator);
}
}
If OwnedProductValidator needs some other class validation, then:
public class OwnedProductValidator : BaseValidator<OwnedProduct, SomeOtherClass>{}

Workaround for new() constraint with parameters in generics

I know, there are a few answers here on SO, which seem to solve my questions, like this and that threads. But in my specific case, there is some difference.
In front my question: Is this a possible/intelligent workaround to manage the new() constraint in generics with parameters?
Assume the following base class:
abstract class BaseClass
{
internal BaseClass()
{
Console.WriteLine("{0}'s ctor (parameterless)", "BaseClass");
}
internal BaseClass(object parent)
{
Console.WriteLine("{0}'s ctor", "BaseClass");
Parent = parent;
}
public object Parent { get; private set; }
}
and interface:
interface IGenerate
{
IGenerate GenerateNew(int x, object parent);
}
The base class is only intended to store a parent object, the interface provides a method to return an object of the implementing class calling its constructor, like this:
class ClassX : BaseClass, IGenerate
{
public ClassX()
{
Console.WriteLine("{0}'s ctor (parameterless)", "ClassX");
}
public ClassX(int x, object parent)
: base(parent)
{
Console.WriteLine("{0}'s ctor", "ClassX");
X = x;
}
public IGenerate GenerateNew(int x, object parent)
{
Console.WriteLine("{0}.GenerateNew()", "ClassX");
return new ClassX(x, parent);
}
public int X { get; private set; }
}
My generic class is intended to generate and store an object of the provided class calling the interfaces method:
class MyGeneric<T> : BaseClass where T : IGenerate, new()
{
public MyGeneric(int x, object parent)
: base(parent)
{
Console.WriteLine("{0}'s ctor", "MyGeneric");
Instance = new T().GenerateNew(x, this);
}
public IGenerate Instance { get; private set; }
}
Another class inherits the generic:
class ClassXSpecifier : MyGeneric<ClassX>
{
public ClassXSpecifier(int x, object parent)
: base(x, parent)
{
Console.WriteLine("{0}'s ctor", "ClassXSpecifier");
}
}
The use of these constructs is something like that:
var classXspecifier = new ClassXSpecifier(5, null);
var classX = (ClassX)classXspecifier.Instance;
Console.WriteLine(classX.X);
Output:
BaseClass's ctor
MyGeneric's ctor
BaseClass's ctor (parameterless)
ClassX's ctor (parameterless)
ClassX.GenerateNew()
BaseClass's ctor
ClassX's ctor
ClassXSpecifier's ctor
5
Again my primary question: Is this a possible/intelligent workaround to manage the new() constraint in generics with parameters?
A secondary question: Why do BaseClass and ClassX need to have a parameterless constructor while they won't be used in any case explicitly? If I remove them, I get the following error:
'ClassX' must be a non-abstract type with a public parameterless
constructor in order to use it as parameter 'T' in the generic type or
method 'MyGeneric'
Thanks in advance, Christian =)
!!! SOLUTION !!!
The provided answer tempt me to do modifications, that the new() constraint could be removed -> so the parameterless constructors could be removed, too.
I deleted the interface and added a static method into BaseClass to generate new objects:
public static BaseClass GenerateNew(Type T, object[] args)
{
return (BaseClass)Activator.CreateInstance(T, args);
}
So the generic class could be reduced to
class MyGeneric<T> : BaseClass
{
public MyGeneric(int x, object parent)
: base(parent)
{
Console.WriteLine("{0}'s ctor", "MyGeneric");
Instance = GenerateNew(typeof(T), new[] { x, parent });
}
public BaseClass Instance { get; private set; }
}
That was it, thanks to all comments, too!
Although you can use CreateInstance, it is not recommended because of the performance and lack of compile-time safety. An alternative is to require the constructor be passed as a delegate.
void GenericMethod<T>(Func<string, T> ctor)
{
T t = ctor("foo");
}
To call the method, using a class called Foo as the generic type: GenericMethod((arg) => new Foo(arg))
args does not need to be defined prior to calling the generic method and is only used to indicate how the parameters of ctor will be used.
This approach also comes with the advantages of being able to use a different constructor, for example:
GenericMethod((arg) => new Foo(arg, 1));
You can also create the object through a static method rather than a constructor, which can use a simplified syntax if the parameters are the same:
GenericMethod((arg) => Foo.Create(arg));
// or
GenericMethod(Foo.Create);
Question
Again my primary question: Is this a possible/intelligent workaround to manage the new() constraint in generics with parameters?
Answer
Your passing a type(ClassX) and want to access an instance function(GenerateNew) without creating an instance -> well that's one problem you need to think about.
You can create a static factory(and\or use IOC) for creating new object's by types.
Question
Why do BaseClass and ClassX need to have a parameterless constructor while they won't be used in any case explicitly?
Answer
This constraint requires that the generic type that is used is non-abstract and that it has a default (parameterless) constructor allowing you to call it.
BTW, you are using the empty ctor by doing new T().

How to Inherit from Generic Parent

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
}

Generic Constraint to allow casting from interface to implementation

I have a small class that implements a dictionary that maps from the type of an interface to an implementation of that interface that extends from a base class. Unfortunately the abstract base class does not implement the interfaces, so once in the dictionary, there seems to be no way to associate the two. There is another method in this class that is dependent on storing the objects as BaseClass (in fact, most of my class is dependent on that--the getter into the dictionary is somewhat of a convenience).
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (!(base is T)) // How to get rid of this check?
{
throw new ArgumentException("base does not implement " + typeof(T).Name);
}
this.dictionary.Add(typeof(T), base);
}
public T Get<T>()
{
BaseClass base;
this.dictionary.TryGetValue(typeof(T), out base);
return (T)(object)base; // How to get rid of (object) cast?
}
Are there any clever constraints I can use to remove the (base is T) check, the cast to object, or both?
Here is the class setup, for reference:
class BaseClass { }
interface IThing { }
class MyClass : BaseClass, IThing { }
dict.Add<IThing>(new MyClass());
IThing myClass = dict.Get<IThing>();
The only way to get the compile-time enforcement you're looking for would be if you have compile-type knowledge of the derived type being added.
For example, if you also specify a type parameter for the class being added then you could constrain that the class implement the interface type parameter:
public void Add<TInterface, TClass>(TClass #base)
where TClass : BaseClass, TInterface {
this.dictionary.Add(typeof(TInterface), #base);
}
So you could do this:
MyClass ok = new MyClass();
dict.Add<IThing, MyClass>(ok);
But not this:
class MyClassNotIThing : BaseClass { }
MyClassNotIThing notOk = new MyClassNotIThing();
dict.Add<IThing, MyClassNotIThing>(notOk);
Aside from that, generic constraints don't offer a means by which to constrain that a known type (i.e. BaseClass) inherit from a generic type parameter.
Here is the solution I ended up using. There are a few tricks that can make the Add() safe without the check (see the link in a comment to cokeman19's answer), but I opted not to do that as I find this code a bit cleaner.
interface IThing { }
abstract class BaseClass
{
internal T AsInterface<T> where T : class
{
return this as T;
}
}
class MyClass : BaseClass, IThing { }
class DictionaryClass
{
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (base is T)
{
dictionary.Add(typeof(T), base);
}
}
public T Get<T>() where T : class
{
return dictionary[typeof(T)].AsInterface<T>();
}
}
Note that this solution does allow calls like:
myClass.AsInterface<IThingItDoesntImplement>()
but this returns null and I made the function internal to prevent strange uses anyway.

Categories

Resources