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);