Suppose you want to set multiple items to a Windows Runtime IVector<T>
. This is common in the cases where the system provides a vector that you are expected to fill with stuff. For example:
// C# var picker = new FileOpenPicker(); picker.FileTypeFilter.Add(".bmp"); picker.FileTypeFilter.Add(".gif"); picker.FileTypeFilter.Add(".jpg"); picker.FileTypeFilter.Add(".png");
Surely there is an easier way to do this than calling Add
multiple times, right?
Yes, there is an easier way, but the easier way depends on what language you are using. Each language expresses the Windows Runtime IVector<T>
in its own language-specific way.
C# projects the IVector<T>
as an System.Collections.Generic.IList<T>
. You can use object and collection initializer syntax to fill the collection as part of the object initialization.
// C# var picker = new FileOpenPicker() { FileTypeFilter = { ".bmp", ".gif", ".jpg", ".png" } };
Note, however, that this syntax works only in an object initializer.
// doesn't work picker.FileTypeFilter = { ".bmp", ".gif", ".jpg", ".png" };
You might be tempted to use List<T>.AddRange()
, but that doesn’t work either because what you have is an IList<T>
, not a List<T>
. Many people have solved this problem by using an extension method.
C++/WinRT exposes the IVector<T>
very close to how it is defined in the ABI. In particular, there is a ReplaceÂAll
method.
// C++/WinRT auto picker = FileOpenPicker(); picker.FileTypeFilter(). ReplaceAll({ L".bmp", L".gif", L".jpg", L".png" });
C++/CX is a bit more annoying because you have to pass a Platform::
Array^
to the ReplaceÂAll
method, and those Array^
types are frustrating to manufacture.
// C++/CX auto picker = ref new FileOpenPicker(); String^ extensions[]{ L".bmp", L".gif", L".jpg", L".png" }; picker->FileTypeFilter->ReplaceAll( ArrayReference<String^>(extensions, _ARRAYSIZE(extensions)));
Sadly, there are no deduction guides for ArrayÂReference
so you end up having to repeat String^
.
JavaScript projects IVector<T>
as a native JavaScript Array
, and those objects have quite a rich panoply of available methods. One that is useful for us today is splice
.
// JavaScript var picker = new Windows.Storage.Pickers.FileOpenPicker(); picker.fileTypeFilter.splice(0, 0, ".bmp", ".gif", ".jpg", ".png");
The JavaScript projection is kind enough to project the original replaceAll
method as well, which leads us to this somewhat simpler version:
// JavaScript var picker = new Windows.Storage.Pickers.FileOpenPicker(); picker.fileTypeFilter.replaceAll([ ".bmp", ".gif", ".jpg", ".png" ]);
The JavaScript example seems a bit weird. `array.splice(0, 0, a, b, c)` does the same as `array.unshift(a, b, c)` (which is shorter) – inserting the elements at the start of the array (not removing anything). You could also do `array.push(a, b, c)` to insert at the end instead. If you wanted to replace the contents, you’d need to write `array.splice(0, array.length, a, b, c)`.
being unable to use collection initializer syntax to assign a collection in C# is a little annoying but can work around it by creating a struct that take a collection as an argument to its constructor and initializes a property to that collection and then use a collection initializer on that property and it just works cause it actually just calls add for each value in the initializer, after the constructor is called
Something like this for the struct
<code>
and then using it like this
<code>Really not something i would rely on to work and wouldn't use it in any...
You just replaced `list = new List{ 0, 1, 2, 3, 4 }` which is 37 characters long with a 102 character long monstrosity where I have to look up the struct definition to understand what it is doing.
So yeah, please don’t use that one in production code or anywhere else except for obfuscation contests 😉