3

Consider the following two overloaded functions. The first one just wraps the single value into a list and passes to the one that takes in multiple values.

I feel like the overloaded single function isn't needed. Is there an easy yet not too hacky method for having just 1 function that can handle a single or an enumerable ?

    public static void Insert<T>(EntityType entityType, long entityId, string shortName, T value, string owner = null, OptionSearch optionSearch = OptionSearch.Name)
    {
        Insert(entityType, entityId, shortName, new List<T> {value}, owner, optionSearch);
    }

    public static void Insert<T>(EntityType entityType, long entityId, string shortName, IEnumerable<T> values, string owner = null, OptionSearch optionSearch = OptionSearch.Name)
    {
        // Do all the stuff and things using a list of values.
    }

Normally I wouldn't care about the overload but with all these parameters (and making them one input object isn't an option) it just makes it seem unneeded.

PS: Related Passing a single item as IEnumerable<T> but that only discusses ways of doing the overload not so much how to get rid of it

CuriousDeveloper
  • 849
  • 2
  • 8
  • 27
  • Can you use `params`? – CompuChip May 31 '17 at 22:07
  • I don't think there is currently a way of doing this. You could if you rearranged your parameters use params to get an array parameter but that is an array rather than an IEnumerable. Depending on what you are doing that might work. Otherwise there was talk of `params IEnumerable` making it into C# but I couldn't find any evidence that it has made it in yet... – Chris May 31 '17 at 22:08
  • if you move the values so they become the last parameter, then you could use `params T[] values`, which would accept both. The catch is that you would change the order of your arguments, so that could be an argument against it – Icepickle May 31 '17 at 22:13
  • It is far from clear what you are really asking here. Taken literally, the question seems nonsensical: you seem to want a single parameter position to somehow be treated as two completely different types, through some unnamed magic. You only have two options, both of them obvious: make the parameter of type `object` (in which case you lose type parameter inference), or move the parameter to the end so you can make it a `params` array (which will require an array to be passed, not `IEnumerable`). It would help if you could explain why you think what you're asking is even remotely reasonable – Peter Duniho May 31 '17 at 22:16
  • 1
    @PeterDuniho I believe it is reasonable because while T and IEnumerable are different types as you say, the IEnumerable can inheritable handle 1 or more T's. The whole overload is for the sole purpose of having a function be able to handle 1 or more T's. If there was some native type that would just know that sending it 1 T or multiple T's it would do what the overload method is doing for free on the back-end and reduce the unnecessary overloaded method. – CuriousDeveloper Jun 01 '17 at 05:50
  • No one is contesting that it makes sense to pass one or more T elements, least of all me. The problem is that you have some specific constraint that makes no sense in the context of the C# method parameter list rules. _"If there was some native type that would just know that sending it 1 T or multiple T's"_ -- that's the part that's unreasonable. What sort of type is supposed to be one T or an `IEnumerable` of Ts? The only thing that would work like that is `object`, and then you have to do silly things like inspect the type and cast it before you actually use it. Way worse than an overload – Peter Duniho Jun 01 '17 at 06:04

2 Answers2

4

There's no way to avoid the overload other than the proposed on the comments, that is: You could get the values parameter to be the last one, change it to an array, and use the params keyword:

public static void Insert<T>(... other parameters... , params T[] values)

Then you will be able to call the method with an array, with a single T parameter, or with multiple comma-separated T parameters. However, you won't be able to use just any IEnumerable<T>.

I really think that having the overload is the best way to do this at the moment. To track the proposal of including IEnumerable<T> params parameters into C# you can use the following link: https://github.com/dotnet/csharplang/issues/179

Fredy Treboux
  • 3,167
  • 2
  • 26
  • 32
1

Sure, just use the one method that takes the IEnumerable as the input, and require the user to cast their single argument to an array like this:

////Bool for example

Insert<bool>(... new bool[] { singleBool }, ...)

And modify the method to:

public static void Insert<T>(EntityType entityType, long entityId, string shortName, IEnumerable<T> values, string owner = null, OptionSearch optionSearch = OptionSearch.Name)
{
    Insert(entityType, entityId, shortName, new List<T> {value}, owner, optionSearch);
}

Although, I just noticed, that the method refers to itself... Make sure it does what you want it to do.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Optimistic Peach
  • 3,862
  • 2
  • 18
  • 29