Can i accept multiple types for one parameter in c#?

Viewed 463

I'm used to typescript, and there i can:

function test(param1: (string | number)) { }

i can also create a type and use it instead:

type testType = (string | number)

function test(param1: testType) { }

does c# have something similar that doesn't require overloading?

-edit

i'm trying to learn unity3d, and i want a function that returs the length of sounds

i have 2 arrays, on for sfx, and other for musics

the tracks are mapped to enums whose values correspont to the track index in the array

public AudioSource[] musics;
public AudioSource[] sfx;

public enum Musics {
  music1, // names are just exemples
  music2,
  music3
}

public enum Sfx {
  sfx1,
  sfx2,
  sfx3
}

i want to write a function that can accept both Musics.music1 and Sfx.sfx1 and return the length of the corresponding track in the array

public float getPlaybackLength(...) {
    ...
    return ...[trackIndex].clip.length;
}

i'm not sure if that's possible or even if it is a good approach

2 Answers

You are really asking (at least) two different questions here: how to have a single method handle different types for a given parameter, and how to have a single variable store different types.

The former is in fact often addressed by adding overloads; e.g. declare both test(string param1) and test(int param1). In some cases, a single generic method would suffice. It depends on how the parameter will actually be used in the method.

As for the latter question, that's a bit more complicated and would depend heavily on the exact reasoning behind wanting a single variable to be able to store different types. In some cases, again, the variable might be declared in a generic context (type or method).

In other cases, one might use the dynamic type, which is a mechanism that defers compilation of the code that uses the dynamic value until runtime when the type is actually known (for obvious reasons, this can make the code a lot slower…it's optimized as well as can be, but it's still adding a lot of overhead).

Bottom line, the short answer to your question:

does c# have something similar that doesn't require overloading?

…lacking any additional information for why you think you need this feature, is that while overloading would in fact be the first choice, it is possible that generic types or methods might address your need.

The above should answer the question you posted here, such as it is. The question is too vague to provide anything more specific. If you need more specific information, you should post a new question that takes the feedback you've received here into account but elaborates on the specific scenario you are trying to address.


Addendum:

Based on your edited question, it seems you want to do something like this:

public float getPlaybackLength(AudioSource[] tracks, FlexibleEnumType trackIndex) {
    return tracks[trackIndex].clip.length;
}

and pass in either a Musics value or Sfx value.

Given that, I'd recommend the following alternative:

public float getPlaybackLength(AudioSource track) {
    return track.clip.length;
}

where you'd call it like this:

Musics trackId = Musics.music1;

float length = getPlaybackLength(musics[(int)trackId]);

Alternatively:

public float getPlaybackLength(AudioSource[] tracks, int trackIndex) {
    return tracks[trackIndex].clip.length;
}

called as

Musics trackId = Musics.music1;

float length = getPlaybackLength(musics, (int)trackId);

Note that even if you wrote a method that took either enum type for that parameter (and you could, using generics), you'd still need to cast the enum value to an int for the purpose of indexing the array. So you might as well cast before passing the value instead, for simplicity.

As I mentioned, you could write a generic method that can accept either enum type, but you wouldn't be able to restrict it to just those two enum types, and the casting in the method body from the enum value to an int is a bit awkward, because you won't be able to cast directly from the type parameter type. It would involve casting to object first, which results in a boxing and unboxing conversion just to accomplish the cast.

If you really want a 100% type-safe approach that involves passing the enum value rather than casting to int for the call, you should just go ahead and write a couple of overloads for the purpose.

One final thought: maybe your AudioSource type could itself provide a convenience property that returns the clip.length property value. If that's not your own type, you could write a user-defined type that wraps an object of that type and provides the convenience property itself. That way, rather than having to keep looking the object up in an array, you can just get the value directly from an object you already have.

Which, by the way, you could of course do from the AudioSource object too, albeit with the property path clip.length…frankly, that doesn't really seem all that bad to me. After all, a convenience property might be called something like ClipLength anyway, which is basically the same amount of typing. Maybe you have other scenarios in mind, but the convenience method you used as an example doesn't really seem to add that much convenience anyway. :)

void PrintName(object name)
{
    // if you want to do something type specific u need to cast the object 
        // in this specific method there is no need for casting to a specific type
    Console.WriteLine(name);
}
Related