Let's say I have a method:
public void ExampleMethod<T>(T x) where T : struct // or new()
{
// example usage, similar to what's actually happening
var z = (T)Enum.Parse(typeof(T), privateFieldOfTypeString);
// do something depending on values of x and z
// possibly using other methods that require them being enums
// or in case of the new() constraint:
// var t = new T() and do something together with x
}
and I want to use it as follows:
public void CallerMethod<S>(S y)
{
if (typeof(S).IsEnum) // or some other invariant meaning that `S` is "new()able"
{
ExampleMethod(y); // won't compile
}
}
So, during run-time I know that S
satisfies the constraint for ExampleMethod<T>
. I know it's possible to call it using reflection, something along the lines of:
this
.GetType()
.GetMethod(nameof(ExampleMethod<object>))
.MakeGenericMethod(typeof(S))
.Invoke(this, new object[] { y });
Is it possible without reflection?
Note: this is a simplified code from a real-life example and obviously I have no control over the signatures of these methods, hence the answers "add the constraint to CallerMethod
" and "remove the constraint from ExampleMethod
" are invalid.
Yes, the whole thing should be redesigned so the whole problem wouldn't appear at all. But as often in real-life "the whole thing" is too big, too coupled and too risky to rewrite. Some requirements have changed in an unexpected way - hence the apparent code smell, which I'm trying to minimize by hiding it in a single nasty-looking place.
You could use dynamic
:
if (typeof(S).IsEnum)
{
ExampleMethod((dynamic)y);
}
You could utilise operator overloading; define multiple explicit versions of CallerMethod
that can all successfully make a follow on call to ExampleMethod
CallerMethod(Enum1 value) { ExampleMethod(value); }
CallerMethod(Enum2 value) { ExampleMethod(value); }
CallerMethod(Enum3 value) { ExampleMethod(value); }
etc.
If there are a large number of growing types that need a version of CallerMethod
you could write a T4 template to generate a partial
class with all implementations.
If the enum types are known, one possibility, though verbose, would be to convert to known types.
For example, as a starting point,
public void CallerMethod<S>(S y) {
if (typeof(S).IsEnum) {
if (y is KnownEnum) {
var z = (KnownEnum)Enum.Parse(typeof(S), y.ToString());
ExampleMethod(z);
}
if (y is KnownEnum2) {
var z = (KnownEnum2)Enum.Parse(typeof(S), y.ToString());
ExampleMethod(z);
}
//...
}
}
In your specific case you can just cast to an int.
public void CallerMethod<S>(S y)
{
if (typeof(S).IsEnum)
{
ExampleMethod((int)y);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.