 |
|
 |
not very oo
cheers,
Donsw
My Recent Article : CDC - Change Data Capture
|
|
|
|
 |
|
 |
Write a method that uses a params construct like this:
public Foo(params object[] _data) { // do something }
And now, first call it with 2 arrays:
object[] array1, array2;
Foo( array1, array2 );
This will work fine. _data = object[2]{ array1, array2 }.
Now, call it with only 1 array:
Foo( array1 );
And notice a very unexpected result! You would expect _data = object[1]{ array1 }. But it isn't! Instead, _data = array1. I.o.w. if you pass 1 object[], it doesn't get wrapped into the params object[].
A C# bug?
Philippe Dykmans
Software developpement
Advanced Bionics Corp.
|
|
|
|
 |
|
 |
I guess you're saying that if you pass in multiple arrays it evaluates each as a separate parameter, essentially creating an array of arrays?
I'm not sure that it would be a bug, but then again I suppose that really it could have been translated either way.
In any case, very good point - definitely something to keep in mind while you use it.
|
|
|
|
 |
|
 |
The fact that this case i described is the ONLY exception in which the params construct behaves different from what the documentation says, and the fact that the documentation does not mention this exception is what makes me think that it's a bug rather than a 'by design' feature.
In short, this is what params does right now:
- It gets n formal values -> return them in a object[n] array
- It gets 0 formal values -> return an empty object[0] array
- It gets 1 formal value -> return it in a object[1] array EXCEPT if the formal value is an array.
If you think of it, it really doesn't make sence... And the nasty thing is that you cannot correct it in the params function. It has to be done by a typecast in the caller, like so:
Foo( params object[] _data ) { // do something... }
Foo( (object) new object[] { "1", "2" } );
By casting your object[] array to plain object, the compiler translates it correctly.
Regards,
Philippe
Philippe Dykmans
Software developpement
Advanced Bionics Corp.
|
|
|
|
 |
|
 |
philippe dykmans wrote: A C# bug?
Not really. The method signatures match exactly in the second case (where you pass an object[]), and the params modifier doesn't come into the picture at all.
|
|
|
|
 |
|
 |
That's indeed what happens. But i think that's not what's supposed to happen because it makes the params construct non-generic. From the caller's point of view, the object[] parameter is just an object like any other. So, why does it get different treatment in the callee? An object is an object...
Ok, if we don't call it a bug. Isn't it at least 'unexpected'?
Regards,
Philippe
Philippe Dykmans
Software developpement
Advanced Bionics Corp.
|
|
|
|
 |
|
 |
I realize that this comment is a little old but...
I think you didn't understand the params key word
when you have
public Foo(params object[] _data)
you are expecting one of two things:
1 - an array of objects or
2 - a list of objects separated by comma
- When you call
Foo( array1 );
you fell in the first case.
- When you call
object[] array1, array2;
Foo( array1, array2 );
and _data = new object[2]{array1, array2}
you fell in the second case - but the only reason this compiles is because "everything" is object, so array1 and array2 are considered objects in the context (instead of an array of objects)
If in the constructor of Foo you won't be able to access the elements of array1 unless you unbox it to object[].
Try to change everything to string and see what happens.
|
|
|
|
 |
|
 |
I've never come across the params keyword. Might come in handy one day.
Couldn't you use the follwing as an alternative to the __arglist:
public void ProcessList(params object[] args)
{
foreach (object value in args)
{
Console.WriteLine(
"Arg {0} ({1})",
value,
value.GetType());
}
}
// then call it like this
ProcessList("Jim",
1,
false,
(new StringBuilder()).Append("howdy"));
This keeps things documented and is neater in code (I think so, anyway).
|
|
|
|
 |
|
 |
I wouldn't recommend using __arglist at all, it's undocumented and could be removed at any time.
The params object array is a much better idea if you need to go that route - You'll notice near the end of the post I did some performance tests (nothing hardcore) and didn't find any significant difference between the two.
Thanks
|
|
|
|
 |
|
 |
Did you benchmark the performance of the two solutions? and does the second one involve boxing value types or not?
|
|
|
|
 |
|
 |
I did a few tests on using a StopWatch on a single machine -- not exactly hardcore testing or anything -- but I didn't see any notable difference in execution times. Someone might want to check on my results anyways though
Since the second uses an 'params object array', anything being passed in is going to be unboxed as usual. The __arglist appears just to be a complicated way to do the exact same thing.
|
|
|
|
 |
|
|
 |
|
 |
Peter Bromberg (MS MVP) also wrote a small article on __arglist. For people who are interested: http://www.eggheadcafe.com/articles/20030114.asp[^]
The most important part was his conclusion:
Curious users should note that since the above code examples use undocumented keywords, they aren't guaranteed to work in future versions of C#. The params keyword is, of course documented and you can accomplish a similar task using it. I found at least one tech-talk sponsored by Microsoft where a user asked about whether MS planned to document any of these. The answer was "Why should we?". Go figure.
|
|
|
|
 |
|
 |
StiGMaTa_Dev wrote: Why should we?
Yeah, I'm really wondering why should Microsoft add it?
|
|
|
|
 |
|
 |
I agree -- I'm not sure how long it has been around, IMO it looks like it was meant to be an early version of the 'params' keyword -- just way too complicated
|
|
|
|
 |
|
 |
I think it was here since the .Net 1.0. At least it was part of the first SSCLI version which appeared in 2002.
|
|
|
|
 |
|
 |
Does the params keyword support generics? If not, this would be a great reason to support the other it; unless, of course, they gave params generics support.
Regards,
-B
"[F]reedom isn't a licence, it's responsibility." [David Gerrold, Author's Note in "The Man Who Folded Himself", 2003, p. 119]
|
|
|
|
 |
|
 |
Yes, you can use Generics with params, something like this...
public static void Call<T>(params T[] array) {
foreach (T item in array) {
Console.WriteLine(item.ToString());
}
}
|
|
|
|
 |
|
 |
But that only allows you to pass one type, correct?
Regards,
-B
"[F]reedom isn't a licence, it's responsibility." [David Gerrold, Author's Note in "The Man Who Folded Himself", 2003, p. 119]
|
|
|
|
 |
|
 |
Correct, params allows only one type and it has to be the last argument in your method.
It seems like it should allow you to supply a params keyword for any of the arguments so long as there wasn't any types that conflicted with each other (like an params object with a params string), but it doesn't - too bad.
|
|
|
|
 |
|
 |
cheers. I didn't know about the params modifier. It seems much more natrual to pass the objects individually than to produce the array first.
|
|
|
|
 |