3

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!

1
  • 1
    Just a warning in advance: the fact that a type is a value type does not necessarily mean that it is a valid generic type argument for a struct constraint. Nullable value types cannot be used with either class or struct constraints. Commented Feb 4, 2015 at 21:01

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you! Never thought a celebraty like yourself would answer one of my questions ;)
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.