A: 

Unfortunately, generics cannot handle this situation. At least, not well. If you make your methods generic, then just about any type can be passed into them. There won't be an adequate where clause on the generics to limit it to just string and int. If your methods are going to do specific int/string related operations inside them, then generics wont work at all.

Generics in C# are not nearly as powerful as templates in C++, and yes they can cause some major headaches at time. It just takes time to get used to them and get a feel for what they can and cannot do.

Matt Greer
It's important to note that they don't handle this situation well purely based on parameter types. Specifically, _"A type used as a constraint must be an interface, a non-sealed class or a type parameter."_ Intrinsic type int and sealed class string just don't work for constraining the generic.
Marc
I don't need to narrow this down to `int` and `string` (and whatever types will be added). I don't care if this blows at run-time. If the arguments passed in are wrong, then a run-time exception is fine. I just don't want to have to type 2^4 functions with four arguments (and increase that to 3^4 when somebody needs this to deal with `double` as well).
sbi
+4  A: 

Your true problem here is most likely one of design, rather than something generics can be used for. Generics should be used for things that are actually type-agnostic, not as a catch-all to make life a bit easier. Perhaps try posting some actual example code you're using, and someone may have an idea about how to redesign your solution in a way that will allow you to extend it without so much headache.

As a teaser, consider something like this:

public void DoSomethingConditionally<T>(T key, Func<T, bool> BooleanCheck, Action<T> WhatToDo)
{
    if (BooleanCheck(key)) WhatToDo(key);
}

And you could call it like this:

DoSomethingConditionally<String>("input", v => v == "hello", s => Console.WriteLine(s));

I've used lambda expressions here, but you could just as easily predefine a few Func<>s that perform some common expressions. This would be a much better pattern than method overloading, and would force you to handle new input types at design time.

drharris
I have added some explanations to the question. Feel free to propose a better design.
sbi
One potential better design proposed in my answer.
drharris
@drharris: ISWYM. But that would require the caller of `g()` to specify what to do with either `int` or `string`. That's not what I want. I want to be able to call `g()`, passing `int` and `string` (per `ref` and `out`, BTW), as I see fit, letting `g()` deal with the gory details of how to fill them in.
sbi
Keep in mind you could still have a few `g()` overloads that simply automated the calls to `DoSomethingConditionally()`, filling in the functions accordingly to the variable types. This solution is mainly useful for encapsulating that often-repeated functionality of (if some condition is met, perform this action).
drharris
A: 

If you are using c# 4.0 you can do this with the option parameter Or you can use object

Foo(object o)
{
  if (o is int){   }
  else if (o is string){   }
}

Or you can use the generic method Foo<T>(T o){ }

Waleed A.K.
This is a great way to simplify the number of methods, but it doesn't really reduce lines of code. In addition, it doesn't allow you an easy way to specify that only certain types should be able to call it. I love generic methods and the option parameter, but you typically want to use them in situations where any type can be passed into the method and it works the same way.
drharris
This is C# 3, strictly. `:(`
sbi
Only the optional parameters are c# 4.0
Waleed A.K.
adding the `where` clause to the generic definition will restrict the types to which it can be applied.
David Lively
+1  A: 

Use a list of objects.

In the case the number of parameters are unknown at planning time, just use a list of objects. Something like:

void g(params object[] args) {
    foreach (object arg in args) {
         if ((arg is int) && (foo((int)arg))) baz((int)arg) else
         if ((arg is string) && (foo((string)arg))) baz((string)arg)
    }
}

(Assuming you have bool foo(int), bool foo(string)...)

So you can call:

g(p1, p2);
g(p1);
g(p1, p2, p3)

with any combination of the types, since every reference derives from object (which it could be many more types than required, int and string, but could be handy in future to support more other types).

This is possible since you could use Reflection to recognize the type at runtime.

Another way to execute a sequence of operation is the use of interfaces, defining the action to execute at certain conditions, on certain objects.

interface IUpdatable {
    void Update(object[] data);
}

class object1 : IUpdatable { public void Update(object data) { baz(data); } }
class object2 : IUpdatable { public void Update(object data) { baz(data); } }

void g(params IUpdatable[] args) {
    foreach (IUpdatable arg in args) {
         arg.Update(args);
    }
}

But this way you have to model p1 and p2 (but also p3, as objects implementing an interface, which could be not possible.

Luca
Please read what I added to the question later on. I do have a list of strings _up to this point_, but from then on I need these to be parsed into actual variables.
sbi
+5  A: 

Consider using inheritance for this case. I am assuming that foo, bar and baz are inherent to the type (int or string in your case). If this is not true please correct or comment this answer.

using System;

namespace ConsoleApplication3
{
    abstract class Param
    {
        public abstract bool Foo();
        public abstract bool Bar();
        public abstract void Baz();

        public static IntParam Create(int value)
        {
            return new IntParam(value);
        }

        public static StringParam Create(string value)
        {
            return new StringParam(value);
        }
    }

    abstract class Param<T> : Param {
        private T value;

        protected Param() { }

        protected Param(T value) { this.value = value; }

        public T Value {
            get { return this.value; }
            set { this.value = value; }
        }
    }

    class IntParam : Param<int>
    {
        public IntParam() { }
        public IntParam(int value) : base(value) { }

        public override bool Foo() { return true; }
        public override bool Bar() { return true; }

        public override void Baz()
        {
            Console.WriteLine("int param value is " + this.Value);
        }
    }

    class StringParam : Param<string>
    {
        public StringParam() { }
        public StringParam(string value) : base(value) { }

        public override bool Foo() { return true; }
        public override bool Bar() { return true; }

        public override void Baz()
        {
            Console.WriteLine("String param value is " + this.Value);
        }
    }

    class Program
    {
        static void g(Param p1)
        {
            if (p1.Foo()) { p1.Baz(); }
        }

        static void g(Param p1, Param p2)
        {
            if (p1.Foo()) { p1.Baz(); }
            if (p2.Bar()) { p2.Baz(); }
        }

        static void Main(string[] args)
        {
            Param p1 = Param.Create(12);
            Param p2 = Param.Create("viva");

            g(p1);
            g(p2);
            g(p1, p1);
            g(p1, p2);
            g(p2, p1);
            g(p2, p2);

            Console.ReadKey();
        }
    }
}

This would output:

int param value is 12
String param value is viva
int param value is 12
int param value is 12
int param value is 12
String param value is viva
String param value is viva
int param value is 12
String param value is viva
String param value is viva

For a new supported type you:

  1. create a new class that supports the type and extends Param<T>;
  2. implement Foo, Bar and Baz for that new type;
  3. Create a new g method (just one) that has another parameter.

Specially for 3) this would greatly reduce explosion of methods. Now you write a single g method for any given number of parameters. With previous design you had to write, for n parameters, 2^n methods (n = 1 -> 2 methods, n = 2 -> 4 methods, n = 3 -> 8 methods, ..).

smink
This would still be the same number of methods, just spread across multiple classes. That said, this would be a far, far better and more extensible design than the original solution.
drharris
For the foo, bar and baz methods yes. But I am assuming this depends on the type until futher notice ;). As for the g family only one method for a given number of parameters is now required. The original creates methods that supported all combinations. For n parameters it required 2^n g methods (n = 1 -> 2 methods; n = 2 -> 4 methods; n = 3 -> 8 methods, ...).
smink
That requires callers of `g()` to create a wrapper for every parameter. `<sigh>` I guess I have to give in on this one. Boy, do I miss the brute strength and sheer unlimited (if somewhat twisted) expressiveness of C++' templates...
sbi
+2  A: 

Not as optimal as I would like... but what if foo, bar, and baz had generic versions as well?

static bool foo(int input)
{
    return input > 5;
}
static bool foo(string input)
{
    return input.Length > 5;
}
static void baz(int input)
{
    Console.WriteLine(input);
}
static void baz(string input)
{
    Console.WriteLine(input);
}
static bool foo<T>(T input)
{
    if (input is int) return foo((int)(object)input);
    if (input is string) return foo((string)(object)input);
    return false;
}
static void baz<T>(T input)
{
    if (input is int) baz((int)(object)input);
    else if (input is string) baz((string)(object)input);
    else throw new NotImplementedException();
}
static void g<T>(T input)
{
    if (foo(input))
        baz(input);
}
static void g<T, U>(T input, U inputU)
{
    g(input);
    g(inputU);
}
Matthew Whited
You could also replace the if/else blocks with a Dictionary with delgates... that might make it a little nicer.
Matthew Whited
My C++-trained instincts make me cringe seeing those casts, but all in all this looks like it's the least intrusive variant I have seen. I just got `foo()`, ` bar()`, and `baz()` down to one small function for each type involved (`int` and `string`, currently), so this is what I will try now. (If there will ever be more than half a dozen types involved, I'll try the dictionary approach, but for now, this seems more clutter than real help.)
sbi
This solution is basically emulating exactly what the C# 4.0 compiler can do for you as shown in my solution (achieve multiple-dispatch via runtime overload resolution)... @sbi are you not able to use C# 4.0? Moreover, I don't believe using generics in this case actually buys you anything, you can just use object.
Stephen Swensen
@Stephen: No, C# 4.0 is definitely not an option ATM. And, yes, you're right, as it is, generics don't really buy me anything over `object`. `<sigh>` Did I mention I miss C++' templates?
sbi
@sbi: I've updated my solution with an alternate C# 2.0 compliant version which uses reflection.
Stephen Swensen
A: 

This might be a bit heavy handed, but would encapsulating the different parameters types as classes work?:

public abstract class BaseStuff
{
    public abstract bool Foo();
    public abstract bool Bar();
    public abstract void Baz();

    public void FooBaz()
    {
        if(Foo()) Baz();
    }

    public void BarBaz()
    {
        if(Bar()) Baz();
    }
}

public class IntStuff : BaseStuff
{
    private int input;
    public IntStuff(int input)
    {
        this.input = input;
    }

    public bool Foo()
    {
        //logic using input for example
        return input > 0;
    }

    //implement Bar and Baz using input
}

public class StringStuff : BaseStuff
{
    private string input;
    public IntStuff(string input)
    {
        this.input = input;
    }

    //Implement Foo, Bar and Baz
}

And then have some G methods somewhere:

public void G(BaseStuff stuff1)
{
    stuff1.FooBaz();
}

public void G(BaseStuff stuff1, BaseStuff stuff2)
{
    stuff1.FooBaz();
    stuff2.BarBaz();
}

And you can then call with:

G(new IntStuff(10), new StringStuff("hello"));
G(new StringStuff("hello"), new StringStuff("world"));
Sean Clifford
Ah, smink beat me. His looks tidier too!
Sean Clifford
+1  A: 

If you are using C# / .NET 4.0, you can achieve multiple dispatch using the dynamic feature so you only have to implement a single overload of g based on the number of arguments and the proper foo/bar/baz overloads by type inside each g implementation will be resolved at runtime.

    void g(dynamic p1) { if (foo(p1)) baz(p1); }
    void g(dynamic p1, dynamic p2) { if (foo(p1)) baz(p1); if (bar(p2)) baz(p2); }

Edit:

Even though you are unable to use C# / .NET 4.0, you can still use this approach using reflection. I've added another foo/bar/baz overload for double showing how well this generalizes and allows you to eliminate duplicate g implementations.

    bool foo(int p) {Console.WriteLine("foo(int)=" + p); return p == 0;}
    bool foo(string p) {Console.WriteLine("foo(string)=" + p); return p == "";}
    bool foo(double p) { Console.WriteLine("foo(double)=" + p); return p == 0.0; }

    bool bar(int p) {Console.WriteLine("bar(int)=" + p); return p == 1;}
    bool bar(string p) { Console.WriteLine("bar(string)=" + p); return p == ""; }
    bool bar(double p) { Console.WriteLine("bar(double)=" + p); return p == 1.1; }


    void baz(int p) {Console.WriteLine("baz(int)=" + p);}
    void baz(string p) { Console.WriteLine("baz(string)=" + p); }
    void baz(double p) { Console.WriteLine("baz(double)=" + p); }

    //these object overloads of foo/bar/baz allow runtime overload resolution
    bool foo(object p)
    {
        if(p == null) //we need the type info from an instance
            throw new ArgumentNullException();

        //may memoize MethodInfo by type of p
        MethodInfo mi = typeof(Program).GetMethod(
            "foo", 
            BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, 
            null, 
            new Type[] { p.GetType() }, 
            null
        );

        if (mi.GetParameters()[0].ParameterType == typeof(object))
            throw new ArgumentException("No non-object overload found");

        return (bool)mi.Invoke(this, new object[] { p });
    }

    bool bar(object p)
    {
        if (p == null)
            throw new ArgumentNullException();

        MethodInfo mi = typeof(Program).GetMethod(
            "bar",
            BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
            null,
            new Type[] { p.GetType() },
            null
        );

        if (mi.GetParameters()[0].ParameterType == typeof(object))
            throw new ArgumentException("No non-object overload found");

        return (bool)mi.Invoke(this, new object[] { p });
    }

    void baz(object p)
    {
        if (p == null)
            throw new ArgumentNullException();

        MethodInfo mi = typeof(Program).GetMethod(
            "baz",
            BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
            null,
            new Type[] { p.GetType() },
            null
        );

        if (mi.GetParameters()[0].ParameterType == typeof(object))
            throw new ArgumentException("No non-object overload found");

        mi.Invoke(this, new object[] { p });
    }

    //now you don't need to enumerate your identical implementations of g by type
    void g(object p1) { if (foo(p1)) baz(p1); }
    void g(object p1, object p2) { if (foo(p1)) baz(p1); if (bar(p2)) baz(p2); }
Stephen Swensen
While this would work you would also lose full control over type safety and intelisense. But it should automatically resolve the correct methods at runtime. There could be a possible loss in performance, but if you are using .Net 4.0 this would be a valid option.
Matthew Whited
A: 

You can use code generation to solve this.

Look at Reflection.Emit. You can also generate code with T4 in Visual Studio.

The types are really getting in the way here. You could also try to solve this with a dynamic language or with the C# 4 dynamic keyword.

Jordão
+1  A: 

I would have done this as a comment to @smink, but I don't have enough rep...

If you extend the Param base class to have implicit operators you are back to not having to wrap the contents in code (though the runtime still incurs the wrapping overhead)...

abstract class Param 
{ 
    ...
    public static implicit operator Param(int value)
    { return new IntParam(value); }
} 
StarBright