Workaround for new() constraint with parameters in generics - c#

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

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.

Inheriting constructor with single optional argument

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.

Force a child class to pass itself as the Generic parameter to the base class

I want to force my child classes to pass themselves as as the generic parameter to the parent class.
For example :
class BaseClass<T> where T: BaseClass
{
//FullClassName : Tuple [Save,Update,Delete]
Dictionary<string,Tuple<delegate,delegate,delegate>> dict = new Dictionary...;
static BaseClass()
{
RegisterType();
}
private static void RegisterType()
{
Type t = typeof(T);
var props = t.GetProperties().Where(/* Read all properties with the SomeCustomAttribute */);
/* Create the delegates using expression trees and add the final tuple to the dictionary */
}
public virtual void Save()
{
delegate d = dict[t.GetType().FullName];
d.Item1(this);
}
}
class ChildClass : BaseClass<ChildClass>
{
[SomeCustomAttribute]
public int SomeID {get;set;}
[SomeCustomAttribute]
public string SomeName {get; set;}
}
public class Program
{
public static void Main(string[] args)
{
ChildClass c = new ChildClass();
c.Save();
}
}
Obviously the above code won't compile. I'll restate : I want the child class to pass itself as the generic parameter and not any other child of BaseClass.
(The above code is kind of a psuedo code and will still not compile).
You can do this:
public class BaseClass<T> where T: BaseClass<T> { }
public class ChildClass : BaseClass<ChildClass> { }
But this doesn't force you to use ChildClass as the generic parameter. You could do this public class OtherChildClass : BaseClass<ChildClass> { } which would break the "coontract" that you want to enforce.
The direct answer is that if your accessing a static method then typeof(T) will give you the type for reflection.
However, there is probably better solutions than using reflection. Options:
1) Static constructor on the child class.
2) Abstract method declared in the base class.
I do not know the application, but I get concerned about my design if I feel like using a static constructor, I also get concerned if a base class needs to initialize the child class.
I suggest looking at injection as a solution rather than inheritance. It offers superior unit testing and often a better architecture.
More info (after initial post), this is my preferred solution:
public interface IRegesterable
{
void Register();
}
public class Widget : IRegesterable
{
public void Register()
{
// do stuff
}
}
public class Class1
{
public Class1(IRegesterable widget)
{
widget.Register();
}
}
Hope this helps
The ConcurrentDictionary is being used as a Set<Type>. We can check in the Set<Type> if the type has been initialized. If not we run RegisterType on the type.
public abstract class BaseClass
{
//Concurrent Set does not exist.
private static ConcurrentDictionary<Type, bool> _registeredTypes
= new ConcurrentDictionary<Type, bool>();
protected BaseClass()
{
_registeredTypes.GetOrAdd(GetType(), RegisterType);
}
private static bool RegisterType(Type type)
{
//some code that will perform one time processing using reflections
//dummy return value
return true;
}
}
public class ChildClass : BaseClass
{
}
There are several inefficiencies with this pattern though.
object.GetType() is pretty darn slow, and inefficient.
Even with the HashSet behavior, we are checking for initialization on each instanciation. Its as fast as I can get it, but its still pretty superfluous.

Polymorphism Through Extension Methods?

I have a class library which contain some base classes and others that are derived from them. In this class library, I'm taking advantage of polymorphism to do what I want it to do. Now in a consuming application, I want to change the behavior of some code based on the runtime type of the child classes. So assume the following:
public class Base { }
public class Child1 : Base { }
public class Child2 : Base { }
Now in the consuming application I want do something as follows (note that all of the following classes are in the consuming application and cannot be referenced in the class library):
public interface IMyInterface1 { }
public interface IMyInterface2 { }
public static class Extensions
{
public static void DoSomething(this Base myObj, Object dependency)
{
}
public static void DoSomething(this Child1 myObj, Object dependency)
{
IMyInterface1 myInterface = dependency as IMyInterface1;
if (myInterface != null)
{
//Do some Child1 specific logic here
}
}
public static void DoSomething(this Child2 myObj, Object dependency)
{
IMyInterface2 myInterface = dependency as IMyInterface2;
if (myInterface != null)
{
//Do some Child2 specific logic here
}
}
}
UPDATE:
This does not work. It always calls the extension method of the base class. Is there some other way that will allow me to do this and avoid having to explicitly check for the runtime type? The reasons is because more classes that are derived from the Base could be added and corresponding extension methods could come from some other external assembly.
Thanks in advance.
As #SLaks has already stated you cannot call the method as an extension method (even with a dynamic type) ... you can however call the static method with a dynamic type
So, although this will fail
Base base1 = new Child1();
(base1 as dynamic).DoSomething();
This will work
Base base1 = new Child1();
Extensions.DoSomething(base1 as dynamic);
No, that won't work.
Extension methods are statically dispatched, using the same mechanism as overload resolution.
If you have a variable of compile-time type Base, the compiler will always call the base extension method, regardless of the runtime type.
Instead, you can make the base extension method check the runtime type and call the appropriate other extension method.
I was looking for the same thing just now.
You could add one more method to your extension class like this:
public static void DoSomething(this Base myObj, Object dependency)
{
if(myObj.IsSubclassOf(Base))
{
// A derived class, call appropriate extension method.
DoSomething(myObj as dynamic, dependency);
}
else
{
// The object is Base class so handle it.
}
}
You don't need the if/else check if the base class is abstract (or never used in the wild):
public static void DoSomething(this Base myObj, Object dependency)
{
DoSomething(myObj as dynamic, dependency);
}
[Edit] Actually this won't work in your case as you don't implement support for all derived objects (so could still get infinite recursion). I guess you could pass something to check for recursion but the given answer is the simplest. I'll leave this here as it might spark more ideas.
Below is the minimal example showing how to mimic polymorphism with extension methods.
void Main()
{
var elements = new Base[]{
new Base(){ Name = "Base instance"},
new D1(){ Name = "D1 instance"},
new D2(){ Name = "D2 instance"},
new D3(){ Name = "D3 instance"}
};
foreach(Base x in elements){
x.Process();
}
}
public class Base{
public string Name;
}
public class D1 : Base {}
public class D2 : Base {}
public class D3 : Base {}
public static class Exts{
public static void Process(this Base obj){
if(obj.GetType() == typeof(Base)) Process<Base>(obj); //prevent infinite recursion for Base instances
else Process((dynamic) obj);
}
private static void Process<T>(this T obj) where T: Base
{
Console.WriteLine("Base/Default: {0}", obj.Name);
}
public static void Process(this D1 obj){
Console.WriteLine("D1: {0}", obj.Name);
}
public static void Process(this D2 obj){
Console.WriteLine("D2: {0}", obj.Name);
}
}
Outputs:
Base/Default: Base instance
D1: D1 instance
D2: D2 instance
Base/Default: D3 instance
If you can not use the keyword "dynamic" (older version of .NET), you can use reflection to achieve the same thing.
In place of :
Base base1 = new Child1();
Extensions.DoSomething(base1 as dynamic);
you can write :
Base base1 = new Child1();
MethodInfo method = typeof(Extensions).GetMethod("DoSomething", new System.Type[] { base1.GetType() });
if (method) {
method.Invoke(new object[] { base1 });
}

Why can't we use a constructor with parameter in derived classes

Why is this not possible?
I get the following compiler-error when instantiating "DerivedClass" with a constructor-parameter:
'GenericParameterizedConstructor.DerivedClass' does not contain a constructor that takes 1 argument
But calling a very similar method works.
Why?
class Program
{
static void Main(string[] args)
{
// This one produces a compile error
// DerivedClass cls = new DerivedClass("Some value");
// This one works;
DerivedClass cls2 = new DerivedClass();
cls2.SomeMethod("Some value");
}
}
public class BaseClass<T>
{
internal T Value;
public BaseClass()
{
}
public BaseClass(T value)
{
this.Value = value;
}
public void SomeMethod(T value)
{
this.Value = value;
}
}
public class DerivedClass : BaseClass<String>
{
}
Constructors aren't inherited - it's as simple as that. DerivedClass contains a single constructor - the public parameterless constructor provided by default by the compiler, because you haven't specified any constructors.
Note that this has nothing to do with generics. You'd see the same thing if BaseClass weren't generic.
It's easy to provide constructors for DerivedClass though:
public class DerivedClass : BaseClass<String>
{
public DerivedClass() : base()
{
}
public DerivedClass(string value) : base(value)
{
}
}
The deriving class needs to expose the constructor
public class DerivedClass : BaseClass<String>
{
public DerivedClass(string str) :base(str) {}
}
It would sometimes be helpful if there a way of instructing the compiler to automatically generate for a particular derived class constructors which precisely mimic and wrap all those of the base class. Having such behavior occur by default, however, would be problematic. Many derived classes expect that some of their code will be called whenever an instance of their type is created. Suppose a parent type had two constructors:
parentType(int foo) {...}
parentType(string foo) {...}
and a derived type had one:
derivedType(string foo) {...}
What should be the effect of new derivedType(7);? The compiler would know how to create a new baseType(7);, but if it created a new "blank" derivedType object and then simply called the parent-type constructor, the result would be a derivedType object which had never run any of derivedType's construction code. While some classes wouldn't have any problem with that (and for such classes, the earlier-mentioned hypothetical feature would be helpful), a lot of classes would.
Incidentally, a somewhat-related issue occurs with protected constructors. In some .net languages including at least the current version of C#, if non-abstract type Foo defines a protected constructor, that constructor may only be used to create instances of derived types. In other languages, including the current vb.net, it's possible for code within a derived type to call a protected constructor of the base type to create a new base-type instance.

Categories

Resources