39

Is there a way to declare a generic function that the generic type is of type1 or type2?

example:

public void Foo<T>(T number)
{
}

Can I constraint T to be int or long

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • 1
    [Constraints on Type Parameters (C# Programming Guide)](http://msdn.microsoft.com/en-us/library/d5x73970.aspx) – Cody Gray - on strike Dec 18 '11 at 15:54
  • @BoltClock, Because my code breaks when the parameter isn't one of the primitive(int, long, double...) and I want to get errors on compilation not on RunTime – gdoron Dec 18 '11 at 15:56
  • Related: [Generic method multiple(OR) type constraint](http://stackoverflow.com/q/10833918) – JW Lim Jun 27 '14 at 07:25

7 Answers7

24

For ReferenceType objects you can do

public void DoIt<T>(T someParameter) where T : IMyType
{

}

...

public interface IMyType
{
}

public class Type1 : IMyType
{
}

public class Type2 : IMyType
{
}

For your case using long as parameter will constrain usage to longs and ints anyway.

public void DoIt(long someParameter)
{

}

to constrain to any value types (like: int, double, short, decimal) you can use:

public void DoIt<T>(T someParameter) where T : struct
{

}

for more information you can check official documentation here

Adam Moszczyński
  • 3,477
  • 1
  • 17
  • 18
23

Although you could use a generic constraint to limit the type of each generic argument T, unfortunately there is none that would allow you to enforce at compile time whether T is type1 or type2.

Nor is there any way to enforce at compile time that your generic argument can only be of any primitive type (int, long, double, ...).

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
9

No.

That doesn't make sense; T would not have any usable compile-time type in the method.

Instead, you should make two overloaded methods.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 3
    I think it does make sense. I have a code that if you pass a parameter different then double, decimal, float, int, long etc' will brake. I want to verify this at compilation. Doesn't make sense? – gdoron Dec 18 '11 at 15:59
  • 1
    @gdoron: From your point of view, it makes sense. From the compiler's point of view, it does not make sense, since `T` would not be a usable type. – SLaks Dec 18 '11 at 16:02
  • In this case the compiler can treat `T` as the common of type1 and type2, where there is no relation `T` is `object`... – gdoron Dec 18 '11 at 16:09
  • 8
    I think this is a reasonable question, if you read between the lines. It seems he is asking for a constraint such as `where T : number` which unfortunately doesn't exist. Still, it would be a construct that makes sense... – Max Dec 18 '11 at 16:28
5

Use overloaded methods instead:

public void Foo(int number)
{
} 

public void Foo(long number)
{
}

You cannot perform arithmetical operations on generic types anyway. Note that you can pass an int value to a long parameter. It will automatically be converted to long. Having just a single method with a long parameter could therefore be sufficient.

Older programming languages worked after the principle "There can be only one". C# allows you to have several methods with the same name in the same class, interface or struct. These methods must have a different signature. This means, that they must have a different number of parameters or parameters with different types (or both). This is called method overloading.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • I can't write 20 method for each numeric value type. this is what Generics **should have** solved – gdoron Dec 18 '11 at 16:32
  • 1
    Artihmetic operations are not supported on generic type parameters. See `System.Text.StringBuilder` for an example. It defines more than 20 `Append()` overloads for differents types. – Olivier Jacot-Descombes Dec 18 '11 at 16:42
3

I know this is an old question, and this doesn't perfectly answer it, but you can do this with a single method, rather than creating multiples, or using generic constraints... especially useful if you have 20 odd types to check.

Obviously you don't get the compiler type checking as you do when using a constraint, but this can help in certain circumstances...

public void MyMethod<T>()
{
    if (!typeof(T).Equals(typeof(int)) &&
        !typeof(T).Equals(typeof(long)))
            throw new Exception("T must be int or long");

    //your logic here
}
Detail
  • 785
  • 9
  • 23
0

I also had this problem and I think I found a better solution (assuming an overloaded version of your method is insufficient):

Mixing Type1 and Type2 without any parallels does not make any sense as has been written already. So there has to be any method or property accessed for both object types. To make sure for the compiler that these methods or properties are available for your object, group Type1 and Type2 by creating an interface MyInterface and implementing it by Type1 and Type2:

interface MyInterface {
  void MyCommonMethod();
  bool MyCommonProperty { get; }
}

class Type1 : MyInterface {
  void MyCommonMethod() {
    // TODO: Implement it for Type1
  }

  bool MyCommonProperty {
  get {
    // TODO: Implement it for Type1
  }
  }
}

class Type2 : MyInterface {
  void MyCommonMethod() {
    // TODO: Implement it for Type2
  }

  bool MyCommonProperty {
  get {
    // TODO: Implement it for Type2
  }
  }
}

Now, to rewrite your Foo method to accept both Type1 and Type2, constraint T to be an MyInterface object:

public void Foo<T>(T number) where T : MyInterface
{
  throw new NotImplementedException();
}

I mope this might be helpful. :)

KnorxThieus
  • 567
  • 8
  • 17
0

I don't think this is currently possible.

This question about creating a math library sort of covers the same ground, and includes some work arounds.

Community
  • 1
  • 1
Jon Egerton
  • 40,401
  • 11
  • 97
  • 129