Reputation: 14851
I'm working with two third-party libraries, and racking my brain over a way to solve this particular issue. I'm implementing an interface which will pass me objects of type object
, and in a good number of the calls, I need to pass them into a generic method that expects a type with class and new()
constraints defined.
I know that any object I pass through will meet these constraints, but as far as I can see, there's no simple way I can specify to a generic method that an object satisfies these criteria. An interface can't specify constraints on constructors, and an abstract class isn't permitted as a type argument to the generic method.
The objects being passed in in this case are known and controlled by me, but the signature of both Delete methods can't be modified. Ideally I'd be able to just implement an interface guaranteeing the parameterless constructor criteria, but that doesn't seem to be an option.
Here's an example of what I'm talking about:
public void Delete(object toDelete) {
_repo.Delete(toDelete) // signature here is _repo.Delete<T>(T obj) where T : class, new()
}
To give some background and hopefully explain things - the "Delete" call is an implementation of IUpdatable
in ADO.NET Data services, while the _repo.Delete<T>
call is from SubSonic
. I have one DataContextProvider
class that will be handling these requests (and other similar ones) for every class that I'm exposing through my model, so a direct cast to a specific class isn't feasible. I can guarantee that the classes always are classes and have a parameterless constructor, but I cannot say from the DataContext
that there are only a fixed set of classes that may be passed down - ideally I'd like the DataContext
to work with new classes without modification.
Upvotes: 2
Views: 411
Reputation: 391326
You need to use reflection, you need to get the MethodInfo object for the method to call on your repository, and invoke it dynamically.
Note that there could be a much simpler way to do this, but it sounds to me that you have tried this, otherwise it would be the obvious solution.
Since your "_repo" variable must be of a specific type, like Repository<Employee>
, you could perhaps just cast it, like this?
_repo.Delete(toDelete as Employee);
// or
_repo.Delete((Employee)toDelete);
or, if it's generic:
_repo.Delete(toDelete as T);
If that's not an option, due to code you haven't shown, you need to resort to reflection.
Here's the example:
using System;
using System.Reflection;
namespace ConsoleApplication14
{
public class Program
{
static void Main(string[] args)
{
Dummy d = new Dummy();
EntityType e = new EntityType();
d.Delete(e);
Console.In.ReadLine();
}
}
public class EntityType
{
public EntityType()
{
}
}
public class Dummy
{
private Repository<EntityType> _repo = new Repository<EntityType>();
public void Delete(object toDelete)
{
Type t = _repo.GetType();
Type genericType = t.GetGenericArguments()[0];
MethodInfo mi = t.GetMethod("Delete",
BindingFlags.Public | BindingFlags.Instance,
null, new Type[] { genericType }, new ParameterModifier[0]);
// _repo.Delete(toDelete);
mi.Invoke(_repo, new Object[] { toDelete });
}
}
public class Repository<T>
where T: class, new()
{
public void Delete(T value)
{
Console.Out.WriteLine("deleted: " + value);
}
}
}
Upvotes: 3
Reputation: 660004
I know that any object I pass through will meet these constraints
Its a public method. You don't have to worry about any object that you pass in. You have to worry about any object that anyone passes in.
If you know that the object meets those constraints, do you also know what type the object is? If so, then just cast it to that type.
Upvotes: 2
Reputation: 269348
I suppose that this is repeating what you already know, but if you really can't alter either of those Delete
methods then you're stuck.
The outer method takes a plain object
as an argument and the inner method requires a T
argument where T
meets the class, new()
constraint. Unfortunately, there's no way that those two can be reconciled without alterations.
Upvotes: 1
Reputation: 38367
You can use reflection with the GetConstructors method to verify that the type has a parameterless constructor. Is that what you mean by new() constraints?
Upvotes: 0