Okay I'm looking for some input, I'm pretty sure this is not currently supported in .NET 3.5 but here goes.
I want to require a generic type passed into my class to have a constructor like this:
new(IDictionary<string,object>)
so the class would look like this
public MyClass<T> where T : new(IDictionary<string,object>)
{
T CreateObject(IDictionary<string,object> values)
{
return new T(values);
}
}
But the compiler doesn't support this, it doesn't really know what I'm asking.
Some of you might ask, why do you want to do this? Well I'm working on a pet project of an ORM so I get values from the DB and then create the object and load the values.
I thought it would be cleaner to allow the object just create itself with the values I give it. As far as I can tell I have two options:
1) Use reflection(which I'm trying to avoid) to grab the PropertyInfo[] array and then use that to load the values.
2) require T to support an interface like so:
public interface ILoadValues { void LoadValues(IDictionary values); }
and then do this
public MyClass<T> where T:new(),ILoadValues
{
T CreateObject(IDictionary<string,object> values)
{
T obj = new T();
obj.LoadValues(values);
return obj;
}
}
The problem I have with the interface I guess is philosophical, I don't really want to expose a public method for people to load the values. Using the constructor the idea was that if I had an object like this
namespace DataSource.Data
{
public class User
{
protected internal User(IDictionary<string,object> values)
{
//Initialize
}
}
}
As long as the MyClass<T>
was in the same assembly the constructor would be available. I personally think that the Type constraint in my opinion should ask (Do I have access to this constructor? I do, great!)
Anyways any input is welcome.
As stakx has said, you can't do this with a generic constraint. A workaround I've used in the past is to have the generic class constructor take a factory method that it can use to construct the T:
public class MyClass<T>
{
public delegate T Factory(IDictionary<string, object> values);
private readonly Factory _factory;
public MyClass(Factory factory)
{
_factory = factory;
}
public T CreateObject(IDictionary<string, object> values)
{
return _factory(values);
}
}
Used as follows:
MyClass<Bob> instance = new MyClass<Bob>(dict => new Bob(dict));
Bob bob = instance.CreateObject(someDictionary);
This gives you compile time type safety, at the expense of a slightly more convoluted construction pattern, and the possibility that someone could pass you a delegate which doesn't actually create a new object (which may or may not be a major issue depending on how strict you want the semantics of CreateObject to be).
If you can create common base class for all of T ojects that you are going to pass to MyClass as type parameters than you can do following:
internal interface ILoadValues
{
void LoadValues<TKey, TValue>(IDictionary<TKey, TValue> values);
}
public class Base : ILoadValues
{
void ILoadValues.LoadValues<TKey, TValue>(IDictionary<TKey, TValue> values)
{
// Load values.
}
}
public class MyClass<T>
where T : Base, new()
{
public T CreateObject(IDictionary<string,object> values)
{
ILoadValues obj = new T();
obj.LoadValues(values);
return (T)obj;
}
}
If you cannot have common base class than I think you should go with solution proposed by itowlson.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With