Example 1
Assume a method that decides which method should be used to convert a value.
public static TTarget ConvertValue<TTarget>(object value)
{
Type t = typeof(TTarget);
if (t.IsEnum)
return ParseEnum<TTarget>(value);
else //if ...
return ...;
}
Some methods that handle the value have a generic type parameter with constraints.
public static TEnum ParseEnum<TEnum>(object value)
where TEnum : struct
{
//do something
return ...;
}
The compiler doesn't allow this approach beca开发者_运维技巧use the type TTarget
isn't necessarily a struct
and can become NULL
and thus cannot be used as TEnum
.
Example 2
Assume having a generic method without constraints and a method with additional constraints:
public void DoStuff<T>(T obj)
{
if (obj is IComparable && obj is ICloneable)
DoSpecialStuff<T>(obj);
}
public void DoSpecialStuff<T>(T obj)
where T : IComparable, ICloneable
{
}
This also doesn't work because there is (afaik) no way to cast to multiple interfaces.
Is it possible to reuse a generic type to call a method with additional constraints?
You need to invoke the method using Reflection.
There is no better way.
You should consider calling a non-generic method instead (and passing typeof(TTarget)
as a parameter)—ParseEnum
shouldn't need to be generic.
As SLaks mentions, the only way to achieve this is by using reflection. Here's one way of doing it. (The delegates are cached in a dictionary so that subsequent calls for the same type don't need reflection.)
public static TTarget ConvertValue<TTarget>(this object value)
{
Type t = typeof(TTarget);
if (t.IsEnum)
{
Delegate del = _delegateCache.GetOrAdd(t, t2 =>
Delegate.CreateDelegate(typeof(Func<object, TTarget>),
_parseEnumInfo.MakeGenericMethod(t2));
return ((Func<object, TTarget>)del)(value);
}
else // if ...
return ...;
}
private static readonly MethodInfo _parseEnumInfo =
typeof(YourParentClass).GetMethod("ParseEnum");
private static readonly ConcurrentDictionary<Type, Delegate> _delegateCache =
new ConcurrentDictionary<Type, Delegate>();
public static TEnum ParseEnum<TEnum>(object value)
where TEnum : struct, IComparable, IConvertible, IFormattable
{
// do something
return ...;
}
Or, to match your second example:
public void DoStuff<T>(T obj)
{
if ((obj is IComparable) && (obj is ICloneable))
{
Delegate del = _delegateCache.GetOrAdd(typeof(T), t =>
Delegate.CreateDelegate(typeof(Action<T>),
this,
_doSpecialStuffInfo.MakeGenericMethod(t));
((Action<T>)del)(obj);
}
}
private static readonly MethodInfo _doSpecialStuffInfo =
typeof(YourParentClass).GetMethod("DoSpecialStuff");
private readonly ConcurrentDictionary<Type, Delegate> _delegateCache =
new ConcurrentDictionary<Type, Delegate>();
public void DoSpecialStuff<T>(T obj)
where T : IComparable, ICloneable
{
}
If for each interface of interest you define a version with an "extra" generic parameter T which inherits both the generic interface and ISelf<out T> (I'd suggest that interface contain a single read-only property "self", of type T), and if each class of interest implements ISelf<ItsOwnType>, then if e.g. IFoo<T> inherits from IFoo and T, a routine that needs something to implement both IFoo and IBar could accept a parameter of type IFoo<IBar>. If the passed-in parameter is called X, X will implement IFoo and X.Self will implement IBar. The beautiful thing about this approach is that any such object implementing any combination of interfaces defined in this way can be typecast to something which will implement any combination of those interfaces, in any order. The one weakness with this approach is that it presumes that objects will define ISelf<T>.Self to return themselves, but there's no real guarantee that such an object won't return something else instead.
精彩评论