Home > Enterprise >  Getting a variable that can be multiple types in a function in c#
Getting a variable that can be multiple types in a function in c#

Time:04-07

Lets say I have a function public static int Name(int num){} But I wanna be able to receive more than just an int variable. Not an int and also a string, but either an int or a string (for example). Can I do it without making another function?

CodePudding user response:

I'd handle it in two methods of the same name. This is called overloading the method:

public static int Name(string num){ return Name(int.Parse(num));}

public static int Name(int num){}

This does not have error handling obviously.

I am going to add a little bit more useful example, this allows the user to send either a single email address or a list of them...

public static async Task SendMail(string to, string subject, etc)
{
    await SendMail(new List<string> {to}, subject, etc);
}
public static async Task SendMail(List<string> toList, string subject, etc)
{
    //The process of sending a mail
}

CodePudding user response:

Use a type-union:

Yes. Use a type union, which is a type which represents a value of one specific type from a set of specific types.

C# and .NET doesn't come with built-in support (i.e. first-class union-types), but the excellent OneOf library works just as well:

So your method would be this:

public static Int32 Name( OneOf< Int32, String > num ) // rename `num` to something else if it isn't always going to be a number.
{
    if( num.TryPickT0( out Int32 i32Value, out String strValue ) )
    {
        // do stuff with i32Value
    }
    else
    {
        // do stuff with strValue
    }
}

Because OneOf<T0,T1> has defined implicit conversions from T0 and T1 (but no other types) it means you can invoke your Name method like so:

Int32 name0 = Name( 123 ); // `(Int32)123` is implicitly converted to OneOf<Int32,String> by the compiler for you.

Int32 name1 = Name( "abc" ); // `(String)"abc"` is implicitly converted to OneOf<Int32,String> by the compiler for you.

// But you'll get a compile-time error if you use an unsupported type, e.g.:
Int32 name2 = Name( 456.2f ); // `(Single)456.f` cannot be implicitly converted to OneOf<Int32,String>, so you get a compile-time error.

Alternative: abusing Object as a poor-man's top-type:

.NET does not have any kind of true top-type (that is, a type that can correctly represent a value of any type, including void, as well as representing value-types without boxing); the closest we have is the Object type, which is the supertype of (almost) all reference-types, and also represents boxed value-types.

So if you want the set of parameter types to be unbounded and if you don't mind boxing, and don't mind losing compile-time safety (and so don't mind runtime exceptions...), then you can do it horribly by using Object as a crude top-type:

public static Int32 Name( Object num ) // rename `num` to something else if it isn't always going to be a number.
{
    if( num is Int32 i32Value )
    {
        // do stuff with i32Value
    }
    else if( num is String strValue )
    {
        // do stuff with strValue
    }
    else
    {
        throw new ArgumentException( message: "Unsupported argument type.", paramName: nameof(num) );
    }
}

...but now it's unsafe because the compiler won't give you an error if you pass in a Single (float) value unlike with OneOf<>:

Int32 name0 = Name( 123 ); // Int32 boxed and widened to Object.

Int32 name1 = Name( "abc" ); // String widened to Object.

Int32 name2 = Name( 456.2f ); // Single widened to Object. No compile-time error. Instead this will fail at runtime.

CodePudding user response:

Use the dynamic keyword

public static dynamic foo(int bar) {
    if (bar == 1) {
        return 1;
    } else if (bar == 2) {
        return "two";
    }
    return 0;
}

CodePudding user response:

Instead of specifying the function as an int, you can instead specify multiple outputs:

static (bool approved, string outname) Name(int num)
{
    if (num == 0)
    {
        return (true, "Poul");
    }
    else if (num == 1)
    {
        return (true, "Hans");
    }
    else
    {
        return (false, "Noname");
    }
}

Then you can call the values from the function:

var getName = Name(1);

Console.WriteLine(getName.approved);
Console.WriteLine(getName.outname);
  •  Tags:  
  • c#
  • Related