2

I want to be able to call the generic foo method which has a Nullable param. When the body of the Foo method calls the Foo(), it goes recursive, resulting in a stack overflow (without the .com). Is there a way to have the call in the if statement call the correct overload with the runtime type?

I know changing the names would do it and I understand why the recursion is happening, but don't know of another way to write this.

Thanks for looking.

class Program {
    static void Main(string[] args) {
        int? x = 5;
        int y = 10;
        Foo(x, y);
    }

    static void Foo<T>(Nullable<T> arg, T defaultValue) where T : struct {
        if (arg.HasValue)
            Foo(arg.Value, defaultValue);
    }

    static void Foo(int arg, int defaultValue) {
        Console.WriteLine(string.Format("I'm an int arg={0}, default={1]}", arg, defaultValue));
    }

    static void Foo(string arg, int defaultValue) {
        Console.WriteLine(string.Format("I'm an string arg={0}, default={1]}", arg, defaultValue));
    }

    static void Foo(bool arg, int defaultValue) {
        Console.WriteLine(string.Format("I'm an double arg={0}, default={1]}", arg, defaultValue));
    }
}
jctetter
  • 23
  • 4

1 Answers1

2

Generics are a compile time feature, overload resolution has been decided before the program ever runs. If you want to, as you say, force a runtime decision, you could employ dynamic to achieve that goal (in C# 4+). Short of that, you simply must cast to the applicable type between int and bool otherwise.

  if (arg.HasValue) 
        Foo((dynamic)arg.Value, defaultValue); 

But beware! This only solves your problem for int and bool. Other types could be passed to the generic method, and those will continue to resolve to the generic method on the subsequent call.

 Foo(5.0, 10.0); // would still overflow with your given methods

Follow your initial judgment, if you want to support int, string, and bool, simply have those overloads. If you want to support any given T, create an overload for T.

static void Foo<T>(T arg, T defaultValue)
{
    Console.WriteLine(string.Format("I'm a T arg={0}, default={1}", arg, defaultValue));
}

Overload resolution will still pick int, bool, string, or T? overloads if they are applicable based upon compile time information. All other calls, and the call with arg.Value, will go to this new overload.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
  • thank you Anthony, dynamic did what I would like. As the sample I provided is not my real code, there is a limited number of types which could be passed. I like your idea of changing all methods to one generic method. I'm going to look to see if my overloads can support that. The non-generic methods is legacy code, so I wanted to limit the amount of new code introduced. – jctetter Feb 07 '12 at 16:03