Reputation: 125
I have a dozen methods in my project (C# 2.0) that look like this:
internal bool ValidateHotelStayEntity(DataRow row)
{
return (new HotelStayEntity(row)).Validate();
}
... but for different 'entity' classes. (Okay, not quite that trivial, I've simplified the code here.)
It looks like a good candidate for generics and I came up with this:
internal bool ValidateEntity<T>(DataRow row) where T : EntityBase
{
return (new T(row)).Validate();
}
And of course I get the "Cannot create an instance of the type parametrer 'T' because it does not have the new() constraint" error.
The problem is that these 'entity' classes do not have a public parameterless constructor, nor a way of adding the 'row' data in afterwards. And as EntityBase is part of the company framework I have no control over it (ie I can't change it).
Is there any way around this?
Upvotes: 7
Views: 381
Reputation: 1500725
One simple way is to provide a factory function:
internal bool ValidateEntity<T>(DataRow row, Func<DataRow, T> factory)
where T : EntityBase
{
return factory(row).Validate();
}
and call with:
bool valid = ValidateEntity(row, x => new Foo(x));
Mind you, at that point it's more complicated than just calling
bool valid = new Foo(row).Validate()
in the first place...
It's not really clear what you're trying to achieve in your real context, but this sort of factory/provider approach can certainly be useful at other times. Note that calling a factory delegate can also be considerably faster than using new T()
with a constraint, as I blogged a while ago. Irrevelant in many cases, but worth knowing about.
EDIT: For .NET 2.0 compatibility you'd need to declare the delegate yourself, but that's easy:
public delegate TResult Func<T, TResult>(T input);
If you're really using C# 2 (rather than, say, C# 3 targeting .NET 2.0) then you won't be able to use lambda expressions either, but you can still use anonymous methods:
bool valid = ValidateEntity(row, delegate(DataRow x) { return new Foo(x); });
Upvotes: 15
Reputation: 5150
You can do something like this:
internal bool ValidateEntity<T>(DataRow row) where T : EntityBase
{
return ((T)Activator.CreateInstance(typeof(T), new object[] { row })).Validate();
}
Upvotes: 1
Reputation: 38179
Yet another way could be to involve reflection at the price of compile time checking and decreased performance:
internal bool ValidateEntity<T>(DataRow row)
{
object entity = Activator.CreateInstance(typeof(T), new object[] { row });
MethodInfo validate = typeof(T).GetMethod("Validate");
return (bool) validate.Invoke(entity, new object[]);
}
Note that this would work even if the entities do not have a common ancestor
Upvotes: 3
Reputation: 51339
An example of @JohnSaunders' factory method solution:
internal bool ValidateEntity<T>(DataRow row, Func<DataRow, T> factory) where T : EntityBase
{
return (factory(row)).Validate();
}
Upvotes: 1