如何构造一个空的DeviceInformationCollection?

时间:2019-06-27 17:29:11

标签: windows-runtime c++-winrt

我正在实现一个返回DeviceInformationCollection的接口。实现可能会超时(或失败),在这种情况下,我想返回一个空集合。这是为了允许该接口的客户端始终迭代返回的集合,而不管它是否成功,例如

auto&& devices{ co_await MyType::GetDevicesAsync() };
for (auto&& device : devices)
{
    // Do crazy stuff with 'device'
}

但是,我不知道如何构造一个空的DeviceInformationCollection。以下代码“有效”,但是当客户端使用上面的代码时会导致未定义的行为:

IAsyncOperation<DeviceInformationCollection> MyType::GetDevicesAsync()
{
    // Doing Guru Meditation
    // ...
    co_return { nullptr };
}

我当前的解决方法是返回一个IVector<DeviceInformation>,并在成功后将内部DeviceInformationCollection的项目复制到向量中。这既乏味又低效。我宁愿按原样返回DeviceInformationCollection,并在失败时构造一个空集合。

有没有办法做到这一点?

1 个答案:

答案 0 :(得分:2)

正式地,这不被支持,因为DeviceInformationCollection类没有提供创建其自身的空实例的方法。除非您能在Windows.Devices.Enumeration API中找到一些可以为您完成此功能的函数,否则您会很不幸。

非正式地,我们可以看到DeviceInformationCollection类的默认接口是IVectorView。这意味着该接口表示ABI上的类。因此,您可以使用这些知识来玩弄技巧,但总的来说,这是非常危险的,因为接受DeviceInformationCollection作为输入的API可能会假设其实现是排他的,因此依赖于您可能不知道的某些内部布局。最好每次以多态和安全的方式返回IVectorView。像这样:

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Devices::Enumeration;

IAsyncOperation<IVectorView<DeviceInformation>> Async()
{
    DeviceInformationCollection devices = co_await // ... some async call

    if (devices)
    {
        co_return devices;
    }

    // Returns empty IVectorView...
    co_return single_threaded_observable_vector<DeviceInformation>().GetView();
}

int main()
{
    for (auto&& device : Async().get())
    {
        printf("%ls\n", device.Name().c_str());
    }
}