Reputation: 729
I have too methods:
public TValueType? DoStuffWithValueType<TValueType>(int x, int y)
where TValueType: struct {}
public TRefType DoStuffWithRefType<TRefType>(int x, int y)
where TRefType: class {}
How can i wrap them in a new third method?
The following is not compiling since i cannot persuade the compiler that T
is in fact a struct when calling DoStuffWithValueType
:
public T DoStuff<T>(int x, int y) {
if(typeof(T).IsValueType)
{
return DoStuffWithValueType<T>(x, y);
}
return DoStuffWithRefType<T>(x, y);
}
I already tried overloading DoStuff
, but this attempt failed since generic-constraints are not part of the method signature.
I also tried to get rid of the constraints, but i could not.
Any ideas? Thank you!
Upvotes: 3
Views: 630
Reputation:
Aside from Jon Skeet's use of dynamic
, the cleanest way I can think of, minimising the required reflection, and so keeping as much verified by the compiler as possible, is to call the method through a helper class.
abstract class DoStuffHelper<T> {
public abstract T DoStuff(int x, int y);
}
class DoStuffWithValueTypeHelper<T> : DoStuffHelper<T> where T : struct {
public override T DoStuff(int x, int y) {
return DoStuffWithValueType<T>(x, y);
}
}
class DoStuffWithRefTypeHelper<T> : DoStuffHelper<T> where T : class {
public override T DoStuff(int x, int y) {
return DoStuffWithRefType<T>(x, y);
}
}
public T DoStuff<T>(int x, int y) {
DoStuffHelper<T> helper;
Type helperType;
if(typeof(T).IsValueType)
helperType = typeof(DoStuffWithValueTypeHelper<>);
else
helperType = typeof(DoStuffWithRefTypeHelper<>);
helperType = helperType.MakeGenericType(typeof(T));
helper = (DoStuffHelper<T>)Activator.CreateInstance(helperType);
return helper.DoStuff(x, y);
}
If appropriate for your situation, you can cache the helper classes in a Dictionary<Type, object>
to avoid re-creating them every time.
Upvotes: 2
Reputation: 1499770
You can't, basically - you'd have to invoke the relevant methods with reflection, which is ugly.
Of course you can do this with dynamic typing, which hides the reflection from you:
public T DoStuff<T>(int x, int y) {
dynamic d = this;
if(typeof(T).IsValueType)
{
return d.DoStuffWithValueType<T>(x, y);
}
return d.DoStuffWithRefType<T>(x, y);
}
You may think that's cleaner than doing it manually with reflection - or you may not :)
There's no way that I'm aware of to make the compiler "trust" a type argument where it wouldn't normally do so.
Upvotes: 2