tags:

views:

322

answers:

6

I want to write a generic function to calculate factorial in C# ... like:

 static T Factorial<T>(T n)
        {
            if (n <= 1)
                return 1;

            return Factorial<T>(n - 1);
        }

but obviously having restriction that we can't perform operations on type 'T'. any alternative?

+7  A: 

The problem is that generics don't support operators because they are static methods, and not part of an interface. However, you could probably use Generic Operators, which is available in the Miscellaneous Utility Library.

Nick
+2  A: 

There is no easy way to do this. I have seen some solutions that work around the problem, but they are fairly complicated. That said, if you really want to do this here are a few ideas:

  1. If you can use .Net 4, you can cast n to dynamic and then perform the addition. You lose safety, of course - you could get an exception at runtime

  2. You could always manually check the type from within your factorial function: If n is a short, cast to short, if n is a double, cast to double... etc. That is complicated and defeats part of the value of generics, but the outside API at least looks simple.

Gabe Moothart
+5  A: 

You would need to add a delegate parameter which performs the multiplication. Something like this

delegate T Multiply<T>(T a, T b);

So then your function would be defined like this:

static T Factorial<T>(T n, Multiply func)
{
    ... your code here
}

So when your factorial function is called, the caller would pass in the multiplication function:

int x = Factorial<int>(5, (a,b) => a * b);
Keltex
FYI You might need additional delegate functions / values to be passed in to handle your "1" case.
Keltex
+1 for a clever idea
Gabe Moothart
This indeed gets the job done, but then it's kind of stretching the definition of "Factorial." It might as well be called `DoRecursiveOperation`. After all, I could legally call `Factorial<int>(5, (a,b) => b - a)` and what I'd be getting would not be the result of a factorial at all.
Dan Tao
+1  A: 

When's the last time you took the factorial of a string, or a character? Why do you ever need a factorial of type T????

Besides this has been said numerous (prolly 1 million times now). When you need to use a generic you need to tell the compiler the type.

For instance what if I had a generic stack class? C# needs to know the elements type when I create my stack.

Otherwise it makes no sense for:

Stack<T> s = new Stack<T>();
s.Push(????); //how do I add items to the stack if we don't know what T is?

Instead you need to specify:

Stack<int> s = new Stack<int>();
s.Push(5);
s.Push(7);
JonH
It makes perfect sense to restrict a generic type parameter `T` to a class of types, e.g. `IComparable` types, or merely numerical types. .NET unfortunately doesn’t offer such an interface that is implemented by all built-in numerical types but in theory at least, this is useful. The question after factorials for strings is an *argumentum ad absurdum* and thus a straw-man fallacy.
Konrad Rudolph
@Konrad - The concept makes sense but for this particular question it doesn't.
JonH
@JonH: In Haskell, I might well be tempted to write two versions, one using `Int` for performance, and one using `Integer` (a kind of bignum) to allow very large numbers. Also, I wouldn’t put too much emphasis on the particular example the OP chose, since the question in general crops up in various places.
Konrad Rudolph
@Konrad, if you are writing two versions why cant you cast ?
JonH
I **don’t** actually want to write two versions. I want to write *one* generic piece of code without catering to special cases.
Konrad Rudolph
@Konrad you dont have to hence the cast.
JonH
+1  A: 

This isn't specifically addressing your question about making the method generic, but your method as it stands will never return anything other than 1.

Supposing you were only working with integers, it should look like this:

static int Factorial(int n)
{
    if (n <= 1)
        return 1;

    // note the multiplication in this step
    return n * Factorial(n - 1);
}
Dan Tao
A: 
 public T Factorial<T>(T a, T b, Multiply<T> delegateMutliply, Difference<T> diffDelegate, BaseCondition<T> baseDelegate)
    {
        if (!baseDelegate(a, b))
            return b;

        return delegateMutliply(a, Factorial<T>(diffDelegate(a), b, delegateMutliply, diffDelegate, baseDelegate));
    }

int y = p.Factorial(3, 1, (a, b) => a * b, (a) => --a, (a, b) => (a <= b) ? false : true);

mqpasta