Constructor with optional parameter violates new() constraint - c#

I have a class with this constructor:
public Currency(Guid? vcurrencyUI = null)
: base(vcurrencyUI)
{ }
and I want to use this class with a new() constraint but I get this error:
'Currency' 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 ...
If I split the constructor everything works fine:
public Currency(Guid? vcurrencyUI)
: base(vcurrencyUI)
{ }
public Currency()
: base()
{ }
why do I need to split the constructor?

Because a constructor with a default parameter is not a parameterless constructor.
Default parameters are "filled in" by the compiler at compile time. When you write:
var foo = new Currency();
The compiler generates:
var foo = new Currency(null);
When the class is compiled, the compiler creates a constructor that takes that Guid? parameter, and also generates some metadata that says in effect "if the parameter isn't supplied at compile time, then supply null." But no parameterless constructor is generated for the type.
The new() constraint requires that a parameterless constructor be defined for the type, and it won't accept a constructor with a single default parameter. Most likely that's because the runtime, which ends up having to call the constructor, doesn't understand the concept of default parameters.

Although Jim already answered your question, note that a more general approach might be to allow passing a delegate which would instantiate your concrete class, instead of forcing all your implementations to be parameterless.
I.e. instead of this:
public class Something<T> where T : new()
{
public T CreateInstance()
{
return new T();
}
}
You can pass an explicit delegate which will do any custom instantiation logic:
// note that the constraint is now removed
public class Something<T>
{
private readonly Func<T> _ctor;
public Something(Func<T> ctor)
{
_ctor = ctor;
}
public T CreateInstance()
{
return _ctor();
}
}
// and you can now pass arbitrary constructor logic as a delegate
var x = new Something<Currency>( () => new Currency(null) );
This also allows you to create a helper class and have both options readily available:
public class Something
{
// this allows you to use a parameterless ctor
public static Something<T> Create<T>() where T : new()
{
return new Something<T>(() => new T());
}
// this allows you to specify a custom one
public static Something<T> Create<T>(Func<T> ctor)
{
return new Something<T>(ctor);
}
}

Related

C# generics creating new instances

I'm attempting to write a generic method based on the following myMethod:
void myMethod(myClassA instanceA, myClassB instanceB)
{
instanceA = new myClassA(instanceB);
}
What I've got so far is something like this (myMethod_new), which has some errors:
void myMethod_new<S, T>(S instanceA, T instanceB) where S : new()
{
instanceA = new S(instanceB);
}
However, since I've not mastered how generics work in C#, how should this be implemented?
You can't create a new instance of a generic type if the type has parameters in the constructor. From the docs (emphasis mine):
The new constraint specifies that a type argument in a generic class declaration must have a public parameterless constructor.
One option is to use Activator.CreateInstance and pass in the parameter(s) required. However, that can lead to runtime exceptions since the caller could pass in any type with any format of constructor.
My advice would be to refactor slightly by removing the constructor parameter and create a method to pass that value in, then use an interface to contstrain it all. For example:
// The interface
public interface IHasThing<T>
{
void SetThing(T value);
}
// An implementation of the interface
public class Foo : IHasThing<string>
{
private string _value;
public void SetThing(string value)
{
_value = value;
}
}
And your updated method that returns the new object:
public S myMethod_new<S, T>(T instanceB) where S : IHasThing<T>, new()
{
var s = new S();
s.SetThing(instanceB);
return s;
}
So now you can call the method like this:
var foo = myMethod_new<Foo, string>("bar");

Is there a way to specify a generic type parameter as having a constructor that accepts a string? [duplicate]

I have a wrapper generic class that intended to be used with a set of types. Those types are generated by a utility and are all derived from a base class ClientBase. While ClientBase has only a default constructor, all generated types have default constructor as well as a constructor takes a string as parameter. In the constructor of the wrapper class, I instantiate an instance of the type with the constructor that takes a string. Here is a sample code:
public class ClientBase
{ }
public class GenericProxy<T>
where T: ClientBase, new()
{
T _proxy;
public GenericProxy(string configName)
{
_proxy = new T(configName);
}
}
This code does not compile because type T is not guaranteed to have a constructor that takes a string. Is there a way to define a constrain on the generic class to enforce that the type T must have a constructor that take a string? If this is not possible, what are good alternatives to handle this kind of situation?
It's not possible. I'd like to see "static interfaces" to handle this, but don't expect them any time soon...
Alternatives:
Specify a delegate to act as a factory for T
Specify another interface to act as a factory for T
Specify an interface on T itself for initialization (and add a constraint so that T implements the interface)
The first two are really equivalent. Basically you'd change your proxy class to something like this:
public class GenericProxy<T>
where T: ClientBase, new()
{
string _configName;
T _proxy;
Func<string, T> _factory;
public GenericProxy(Func<string, T> factory, string configName)
{
_configName = configName;
_factory = factory;
RefreshProxy();
}
void RefreshProxy() // As an example; suppose we need to do this later too
{
_proxy = _factory(_configName);
}
}
(I assume you're going to want to create more instances later - otherwise you might as well pass an instance of T into the constructor.)
Unfortunately what you're trying to do isn't possible.
MSDN article on Type Constraints
This does not answer your actual question, constraining a method, but for completeness here's how you can do what you're asking at run time, using reflection:
private T Get<T>(string id)
{
var constructor = typeof(T).GetConstructor(new Type[] { typeof(X), typeof(Y) });
if (constructor == null) throw new InvalidOperationException("The type submitted, " + typeof(T).Name + ", does not support the expected constructor (X, Y).");
var data = GetData(id);
return (T)constructor.Invoke(new object[] { data.x, data.y });
}
As Jon notes, there is no inbuilt support for this - but as an aside you can create a typed delegate to the constructor (faster than reflection) using Expression. The code to do this can be found in MiscUtil (in MiscUtil.Linq.Extensions.TypeExt).
Here is a full working example based on #JonSkeet answer:
using System;
using System.Collections.Generic;
namespace GenericProxy
{
class Program
{
static void Main()
{
GenericProxy<ClientBase> proxy = new GenericProxy<ClientBase>(ClientBase.Factory, "cream");
Console.WriteLine(proxy.Proxy.ConfigName); // test to see it working
}
}
public class ClientBase
{
static public ClientBase Factory(string configName)
{
return new ClientBase(configName);
}
// default constructor as required by new() constraint
public ClientBase() { }
// constructor that takes arguments
public ClientBase(string configName) { _configName = configName; }
// simple method to demonstrate working example
public string ConfigName
{
get { return "ice " + _configName; }
}
private string _configName;
}
public class GenericProxy<T>
where T : ClientBase, new()
{
public GenericProxy(Func<string, T> factory, string configName)
{
Proxy = factory(configName);
}
public T Proxy { get; private set; }
}
}
Expect to see the following output: ice cream

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.

Reading concrete class property within a generic method that doesn't get generic type instance

Suppose I have a generic method that is made generic just for the purpose of returning correct type so upstream callers don't have to cast returned values.
public T Add<T>(string name, string details, ...)
where T: BaseClass
{
// somehow get correct ObjectType
ObjectType type = ??????;
T result = Repo.Add<T>(type, name, details, ...);
...
return result;
}
Problem
The problem of this generic method is that I'm not getting an instance of a concrete class represented with generic type. This means that callers of this method have to explicitly provide generic type as type inference can't be done.
public abstract class BaseClass
{
public abstract ObjectType ActualType { get; }
...
}
Implemented child classes define this property as a quasy constant
public class ConcreteClass: BaseClass
{
public override ObjectType ActualType
{
get { return ObjectType.SomeType; }
}
...
}
Question
Based on generic method call
var result = Add<ConcreteClass>("title", "details");
how can I get the value of ActualType within my Add<T> method? I also tried adding new() generic type constraint, but that doesn't compile as my BaseClass is abstract, so I'm unable to call
new T();
within my method to get that ActualType value.
You need to apply the new() constraint to your Add method like this:
public T Add<T>(string name, string details)
where T: BaseClass, new()
{
T result = new T();
//snip
return result;
}
public abstract class BaseClass { /* snip */ }
public class ConcreteClass: BaseClass { /* snip */ }
Which means this code will work:
var thing = Add<ConcreteClass>("Fred", "Lives in France");
According to the MSDN documentation on the new constraint:
The new constraint specifies that any type argument in a generic class
declaration must have a public parameterless constructor. To use the
new constraint, the type cannot be abstract.
This refers to the type passed in, not the other constraint on your method.

how can force a generic class use T constructor with parameter?

I have a Generic class like this :
public class Mapper<TEntity, TDataAccess>
where TEntity : Common.IEntity
where TDataAccess : DataAccess, new()
{
public TDataAccess DataAccess { get; set; }
public Mapper()
{
DataAccess = new TDataAccess();
}
/*
* ...
* */
}
and data access is like this :
public class DataAccess
{
public DataAccess()
{}
public DataAccess(string tranName)
{}
// CRUD functionality and other data access staff
}
and a inherited class form DataAccess :
public class UserDataAccess:DataAccess
{
public UserDataAccess():base(string.Empty)
{
}
public UserDataAccess(string tranName):base(tranName)
{
// Something to do with user
}
}
and finally UserMapper from Mapper :
public class UserMapper : Mapper<User,UserDataAccess>
{
// Mapping entity properties with datarows columns
}
now imagine that I need to send tranName to given TDataAccess in UserMapper. how can do this without changing DataAccess class ? I can't access the source of DataAccess and also Generics don't realize Types different constructor overloads.
I know that I can have a property on UserDataAccess and fill it whenever I need, but I can't because of thread safety issue.
The User class is a plain entity - it has only properties.
As a case you can use overload of the Activator.CreateInstance() method by specifying constructor parameter:
var dataAccess = Activator.CreateInstance(
typeof(TDataAccess),
new object[] { tranName });
MSDN:
public static Object CreateInstance(
Type type,
params Object[] args
)
Creates an instance of the specified type using the constructor that
best matches the specified parameters.
Generics does not support that. Options:
have a protected virtual TDataAccess CreateDataAccess() method, that by default uses new TDataAccess(), but which can be overridden by UserMapper to create the object any way it likes; call CreateDataAccess() instead of new TDataAccess()
pass in a factory method as a delegate, i.e. a Func<TDataAccess> - so the caller could supply () => new DataAccess("foo"), and use that instead of the new TDataAccess()
use reflection-based code to create the TDataAccess - either Activator.CreateInstance (which supports parameters), or something involving meta-programming (Expression, ILGenerator, etc)

Categories

Resources