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?
where T : new() Means that the type T must have a parameter-less constructor. Having this constraint will allow you to do something like T field = new T(); in your code which you wouldn't be able to do otherwise. You then combine the two using a comma to get: where T : class, new()
Many people are unsatisfied with the restrictions caused by the way generics are implemented in Java. Specifically, they are unhappy that generic type parameters are not reified: they are not available at runtime. Generics are implemented using erasure, in which generic type parameters are simply removed at runtime.
According to oracle documentation, the following points are the disadvantage of generics: Cannot instantiate Generic types with primitive types. Cannot create instances of type parameters. Cannot declare static fields whose types are type parameters.
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); });
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
An example of @JohnSaunders' factory method solution:
internal bool ValidateEntity<T>(DataRow row, Func<DataRow, T> factory) where T : EntityBase
{
return (factory(row)).Validate();
}
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