Unpacking an array into method arguments - c#

As you know C# supports variadic methods through the params keyword:
int Add(params int[] xs) {
return xs.Sum();
}
Which can then be called with any number of arguments you like:
Add(1);
Add(1, 2);
Add(1, 2, 3);
But say I want to call Add using an array of ints1. Is this possible and how (preferably without reflection)? I tried the following but they gave syntax errors (the syntax was pure guessing):
var xs = new[] { 1, 2, 3 };
Add(xs...); // doesn't work; syntax error
Add(params xs); // doesn't work; syntax error
1 My actual use-case is different but I thought this example would be less complicated.

Your method needs a return type:
int Add(params int[] xs) {
return xs.Sum();
}
And to call it with an array you just use the ordinary syntax for method calls:
int[] xs = new[] { 1, 2, 3 };
var result = Add(xs);

The params keyword basically just allows you to take advantage of a little syntactic sugar. It tells the compiler that when it sees
Add(1, 2, 3);
It should convert that to
Add(new int[] { 1, 2, 3});
So to do this from your code, you don't have to do anything special.
int[] parameters = new int[] { ... }
results = Add(parameters);
See the documentation for more details.

As far as I know, you can just call it with an array like you would a normal method:
Add(xs);
Nothing fancy, no params keyword on the method call, no dots.

static void Main(string[] args)
{
int[] tmp = {1, 2};
var sum = Add(tmp);
}
public static int Add(params int[] xs)
{
return xs.Sum();
}
Should work just fine..

If it's anything like Java, you can just call the method with the array as an argument.
This feature is also what makes varargs dangerous, especially if one of the vararg types is also an array...

Related

Pass a List to a params parameter

Is there was a way to pass a List as an argument to a params parameter? Suppose I have a method like this:
void Foo(params int[] numbers)
{
// ...
}
This way I can call it by passing either an array of ints or ints separated by commas:
int[] numbers = new int[] { 1, 5, 3 };
Foo(numbers);
Foo(1, 5, 3);
I wanted to know if there is a way to also be able to pass a List as an argument (without having to convert it to an array). For example:
List<int> numbersList = new List<int>(numbers);
// This won't compile:
Foo(numbersList);
No
Sadly, that's the answer. No, there is not. Not without converting it to an array (for example with .ToArray()).
You would want to change Foo to accept something other than params int[] to do this.
void Foo(IEnumerable<int> numbers) {
}
This would allow you to pass in either an int[] or a List<int>
To allow both ways, you could do this:
void Foo(params int[] numbers) {
Foo((IEnumerable<int>)numbers);
}
void Foo(IEnumerable<int> numbers) {
//Do the real thing here
}
If able to change the existing code, you could always create an overload that accepts a List and passes it to the params method.
void Foo(params int[] numbers)
{
// ...
}
void Foo(IList<int> numbers) => Foo(numbers.ToArray());

C# extension of Enumerable not working

I am trying to add an extension to Enumerable class. but it seems that the extension FindEven() is not picked by the C# compiler. When I build, the compiler spit error :
CS0117 'Enumerable' does not contain a definition for 'FindEven'
Here is my code:
namespace ConsoleApp1
{
static public class Program
{
static IEnumerable<int> FindEven(this IEnumerable<int> array, Func<int, bool> predicte)
{
foreach (var n in array)
{
if (predicte(n))
{
yield return n;
}
}
}
static public void Main(string[] args)
{
int[] numbers = new[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = Enumerable.Select(Enumerable.FindEven(numbers, n => n % 2 == 0), n => n);
foreach (var output in result)
Console.WriteLine(output);
Console.ReadLine();
}
}
}
Anything I did incorrectly here?
[edit]
What I am trying to do here is to see how the 'where' statement in the following LINQ works by making my own version of 'Where', which in this case is 'FindEven' (not a good name I have to admit).
var result = from element in numbers
where element % 2 == 0
select element;
I think if I replace 'FindEven' by 'Where' which is defined in Enumerable[from metadata]... It should be the way LINQ works. But I just can not get the code compiled.
Thanks
Per your edit, it seems you're trying to add your FindEven function to the Enumerable class, but that won't work. When you're calling Enumerable.Where, you're not calling an extension method, you're calling an actual static method that's defined in Enumerable. You can't extend that class that way, because extension methods can't extend static methods, that's not what they're for. They extend instance methods.
The equivalent in your code of calling Enumerable.Where is calling Program.FindEven. That's where the static method is defined. The magic of extension methods is having both Where and FindEven available for an instance of IEnumerable<int>, regardless of where they're defined.
Pre-edit
From the way you call the method, you seem to believe that the extension method adds a new static method to the Enumerable class. It doesn't work that way. The extension method you defined will "add" the method to any instance of IEnumerable<int>, so your code will look like this:
var result = numbers.FindEven(n => n % 2 == 0);
Note, though, that your FindEven doesn't actually FindEven - it just queries using the provided predicate, meaning it's exactly the same as the built-in LINQ Where function. A proper FindEven method would be:
static IEnumerable<int> FindEven(this IEnumerable<int> source)
{
return source.Where(n => n % 2 == 0);
}
This will return a lazily-evaluated IEnumerable<int> containing only the even numbers.
Also, your external Select method does nothing - it just maps every integer to itself, meaning it returns an enumerable that's completely equivalent to its input.
When you define an extension method, you have to call it as it was a member function of your this IEnumerable<int> array parameter
simply replace your call with
var result = Enumerable.Select(numbers.FindEven(n => n % 2 == 0), n => n);
Also note that you created an extension method for IEnumerable<int>, not for Enumerable class
As per your edit, you can use Where function.
namespace ConsoleApp1
{
static public class Program
{
static public void Main(string[] args)
{
int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = numbers.Where(n => n % 2 == 0);
foreach (var output in result)
Console.WriteLine(output);
Console.ReadLine();
}
}
}

Convert generic extension function to simple legacy one

First of all i have some legacy .NET 2 code and i need to transform a extension function to a simple function. So i will start from what i want to achieve.
I have two object arrays which can be any object like int for example
int[] a = new int[] { 1, 2, 3 };
int[] b = new int[] { 4, 5, 6 };
And the only thing i want to do is this:
var y = Concat(a, b);
and then return an array.
The problem is i can't figure out the correct combination in order to transform the following function.
public static class GenericExt
{
public static T Concat<T>(this T[] args, T[] args2)
{
if (!typeof(T).IsArray) throw new ArgumentException("Concat accepts only arrays");
Type elementType = typeof(T).GetElementType();
Array array = Array.CreateInstance(elementType, args.Length + args2.Length);
args.CopyTo(array, 0);
args2.CopyTo(array, args.Length);
return (T)(object)array;
}
}
Any corrections and help are appreciated.
And the only thing i want to do is this: var y = Concat(a, b); and then return an array.
You can't do that unless you're within the same class as the method (or a subclass). You can stop it being an extension method just by removing the this part from the parameter list - but the call would have to be:
var y = GenericExt.Concat(a, b);
Another alternative would be to supply your own ExtensionAttribute class (in the right namespace), and just keep using it as an extension method. The only thing in the framework that is needed for extension methods is that attribute, and you can just copy the declaration out of MSDN. Note that it will then cause problems if you refer to the library from .NET 3.5+ libraries/applications, where the attribute is part of the framework... but if everything is .NET 2, then you should be fine.
Note that the implementation is broken at the moment - at execution time, you're only accepting type arguments which are also arrays... so you'd actually need to pass in an int[][] (with T being int[]) for it to work. You probably just want:
public static T[] Concat<T>(T[] args, T[] args2)
{
T[] array = new T[args.Length + args2.Length];
args.CopyTo(array, 0);
args2.CopyTo(array, args.Length);
return array;
}
But this is a bug in the current implementation which has nothing to do with it being an extension method.

Is there a way to distingish myFunc(1, 2, 3) from myFunc(new int[] { 1, 2, 3 })?

A question to all of you C# wizards. I have a method, call it myFunc, and it takes variable length/type argument lists. The argument signature of myFunc itself is myFunc(params object[] args) and I use reflection on the lists (think of this a bit like printf, for example).
I want to treat myFunc(1, 2, 3) differently from myFunc(new int[] { 1, 2, 3 }). That is, within the body of myFunc, I would like to enumerate the types of my arguments, and would like to end up with { int, int, int} rather than int[]. Right now I get the latter: in effect, I can't distinguish the two cases, and they both come in as int[].
I had wished the former would show up as obs[].Length=3, with obs[0]=1, etc.
And I had expected the latter to show up as obs[].Length=1, with obs[0]={ int[3] }
Can this be done, or am I asking the impossible?
Well this will do it:
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("First call");
Foo(1, 2, 3);
Console.WriteLine("Second call");
Foo(new int[] { 1, 2, 3 });
}
static void Foo(params object[] values)
{
foreach (object x in values)
{
Console.WriteLine(x.GetType().Name);
}
}
}
Alternatively, if you use DynamicObject you can use dynamic typing to achieve a similar result:
using System;
using System.Dynamic;
class Program
{
static void Main(string[] args)
{
dynamic d = new ArgumentDumper();
Console.WriteLine("First call");
d.Foo(1, 2, 3);
Console.WriteLine("Second call");
d.Bar(new int[] { 1, 2, 3 });
}
}
class ArgumentDumper : DynamicObject
{
public override bool TryInvokeMember
(InvokeMemberBinder binder,
Object[] args,
out Object result)
{
result = null;
foreach (object x in args)
{
Console.WriteLine(x.GetType().Name);
}
return true;
}
}
Output of both programs:
First call
Int32
Int32
Int32
Second call
Int32[]
Now given the output above, it's not clear where your question has really come from... although if you'd given Foo("1", "2", "3") vs Foo(new string[] { "1", "2", "3" }) then that would be a different matter - because string[] is compatible with object[], but int[] isn't. If that's the real situation which has been giving you problems, then look at the dynamic version - which will work in both cases.
OK, so let's say that we abandon the other question where you incorrectly believe that any of this is a compiler bug and actually address your real question.
First off, let's try to state the real question. Here's my shot at it:
The preamble:
A "variadic" method is a method which takes an unspecified-ahead-of-time number of parameters.
The standard way to implement variadic methods in C# is:
void M(T1 t1, T2 t2, params P[] p)
that is, zero or more required parameters followed by an array marked as "params".
When calling such a method, the method is either applicable in its normal form (without params) or its expanded form (with params). That is, a call to
void M(params object[] x){}
of the form
M(1, 2, 3)
is generated as
M(new object[] { 1, 2, 3 });
because it is applicable only in its expanded form. But a call
M(new object[] { 4, 5, 6 });
is generated as
M(new object[] { 4, 5, 6 });
and not
M(new object[] { new object[] { 4, 5, 6 } });
because it is applicable in its normal form.
C# supports unsafe array covariance on arrays of reference type elements. That is, a string[] may be implicitly converted to object[] even though attempting to change the first element of such an array to a non-string will produce a runtime error.
The question:
I wish to make a call of the form:
M(new string[] { "hello" });
and have this act like the method was applicable only in expanded form:
M(new object[] { new string[] { "hello" }});
and not the normal form:
M((object[])(new string[] { "hello" }));
Is there a way in C# to implement variadic methods that does not fall victim to the combination of unsafe array covariance and methods being applicable preferentially in their normal form?
The Answer
Yes, there is a way, but you're not going to like it. You are better off making the method non-variadic if you intend to be passing single arrays to it.
The Microsoft implementation of C# supports an undocumented extension that allows for C-style variadic methods that do not use params arrays. This mechanism is not intended for general use and is included only for the CLR team and others authoring interop libraries so that they can write interop code that bridges between C# and languages that expect C-style variadic methods. I strongly recommend against attempting to do so yourself.
The mechanism for doing so involves using the undocumented __arglist keyword. A basic sketch is:
public static void M(__arglist)
{
var argumentIterator = new ArgIterator(__arglist);
object argument = TypedReference.ToObject(argumentIterator.GetNextArg());
You can use the methods of the argument iterator to walk over the argument structure and obtain all the arguments. And you can use the super-magical typed reference object to obtain the types of the arguments. It is even possible using this technique to pass references to variables as arguments, but again I do not recommend doing so.
What is particularly awful about this technique is that the caller is required to then say:
M(__arglist(new string[] { "hello" }));
which frankly looks pretty gross in C#. Now you see why you are better off simply abandoning variadic methods entirely; just make the caller pass an array and be done with it.
Again, my advice is (1) under no circumstances should you attempt to use these undocumented extensions to the C# language that are intended as conveniences for the CLR implementation team and interop library authors, and (2) you should simply abandon variadic methods; they do not appear to be a good match for your problem space. Do not fight against the tool; choose a different tool.
Yes, you can, checking the params length and checking the argument type, see the following working code sample:
class Program
{
static void Main(string[] args)
{
myFunc(1, 2, 3);
myFunc(new int[] { 1, 2, 3 });
}
static void myFunc(params object[] args)
{
if (args.Length == 1 && (args[0] is int[]))
{
// called using myFunc(new int[] { 1, 2, 3 });
}
else
{
//called using myFunc(1, 2, 3), or other
}
}
}
You can achieve something like this by breaking the first element out of the list and providing an extra overload, for example:
class Foo
{
public int Sum()
{
// the trivial case
return 0;
}
public int Sum(int i)
{
// the singleton case
return i;
}
public int Sum(int i, params int[] others)
{
// e.g. Sum(1, 2, 3, 4)
return i + Sum(others);
}
public int Sum(int[] items)
{
// e.g. Sum(new int[] { 1, 2, 3, 4 });
int i = 0;
foreach(int q in items)
i += q;
return i;
}
}
This is not possible in C#. C# will replace your first call by your second call at compile time.
One possibility is to create an overload without params and make it a ref parameter. This probably won't make sense. If you want to change behavior based on the input, perhaps give the second myFunc another name.
Update
I understand your issue now. What you want is not possible. If the only argument is anything that can resolve to object[] it's impossible to distinguish from this.
You need an alternative solution, maybe have a dictionary or array created by the caller to build up the parameters.
Turns out that there was a real issue, and it comes down to the way that C# does type inference. See the discussion on this other thread

Pass array to function from specific index in C# .Net

I am new to C# (previously working on C++), I used to pass array to function with specific index. Here is the code in C++,
void MyFunc(int* arr) { /*Do something*/ }
//In other function
int myArray[10];
MyFunc(&myArray[2]);
Can I do something like this in C# .Net* ?*
As Array is Enumerable, you can make use of LINQ function Skip.
void MyFunc( int[] array ){ /*Do something*/ }
int[] myArray = { 0, 1, 2, 3, 4, 5, 6 }
MyFunc( myArray.Skip(2) );
The linq version is my preferred one. However it will prove to be very very inefficient.
You could do
int myArray[10];
int mySlice[8];
Array.Copy(myArray, 2, mySlice, 0);
and pass mySlice to the function
.NET has the System.ArraySegment<T> structure which addresses this exact use-case.
But I’ve never actually seen this structure used in code, with good reasons: it doesn’t work. Notably, it doesn’t implement any interfaces such as IEnumerable<T>. The Linq solution (= using Skip) is consequently the best alternative.
Probably the most simple way to do this is:
public void MyFunction(ref int[] data,int index)
{
data[index]=10;
}
And call it by this way:
int[] array= { 1, 2, 3, 4, 5 };
Myfunction(ref array,2);
foreach(int num in array)
Console.WriteLine(num);
This will print 1,2,10,4,5
public void MyFunc(ref int[] arr)
{
// Do something
}
int[] myArray = .... ;
MyFunc(ref myArray);
See here for more information on ref!

Categories