I have some legacy code with a method foo which has 700+ overloads:
[DllImport("3rdparty.dll")]
protected static extern void foo(int len, ref structA obj);
[DllImport("3rdparty.dll")]
protected static extern void foo(int len, ref structB obj);
[DllImport("3rdparty.dll")]
protected static extern void foo(int len, ref structC obj);
//and 700 similar overloads for foo...
I'd like to expose these overloaded methods through a single method using generics:
public void callFoo<T>(int len)
where T : new() //ensure an empty constructor so it can be activated
{
T obj = Activator.CreateInstance<T>(); //foo expects obj to be empty, and fills it with data
foo(len, ref obj);
//...do stuff with obj...
}
Unfortunately this returns the errors: "The best overloaded method match for 'foo(int, ref StructA)' has some invalid arguments" and "cannot convert from 'ref T' to 'ref StructA'".
Is there an elegant way to achieve this?
I was hoping that dynamic
would help here, but it doesn't like the ref
. Anyway, reflection should work:
public T callFoo<T>(int len)
where T : new() //ensure an empty constructor so it can be activated
{
T obj = new T();
GetType().GetMethod("foo", BindingFlags.Instance | BindingFlags.NonPublic,
null, new[] { typeof(int), typeof(T).MakeByRefType() }, null)
.Invoke(this, new object[] { len, obj });
return obj;
}
Here's an optimized version that only does the reflection once; should be much faster:
class Test
{
protected void foo(int len, ref classA obj){}
protected void foo(int len, ref classB obj){ }
protected void foo(int len, ref classC obj){}
static readonly Dictionary<Type, Delegate> functions;
delegate void MyDelegate<T>(Test arg0, int len, ref T obj);
static Test()
{
functions = new Dictionary<Type, Delegate>();
foreach (var method in typeof(Test).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (method.Name != "foo") continue;
var args = method.GetParameters();
if (args.Length != 2 || args[0].ParameterType != typeof(int)) continue;
var type = args[1].ParameterType.GetElementType();
functions[type] = Delegate.CreateDelegate(
typeof(MyDelegate<>).MakeGenericType(type), method);
}
}
public T callFoo<T>(int len)
where T : new() //ensure an empty constructor so it can be activated
{
T obj = new T();
Delegate function;
if (!functions.TryGetValue(typeof(T), out function)) throw new NotSupportedException(
"foo is not supported for " + typeof(T).Name);
((MyDelegate<T>)function)(this, len, ref obj);
return obj;
}
}
First - since you have where T : new()
you can just state T obj = new T();
instead of T obj = Activator.CreateInstance<T>();
Now, for the other issue, have a lot of functions like this in one class is chaos.
I would define an interface
public interface IFoo
{
void foo(int len);
}
and make all the classes implement it. And then:
public void callFoo<T>(int len)
where T : IFoo, new() //ensure an empty constructor so it can be activated
{
T obj = new T();
obj.foo(len);
}
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