二十五、CSharp 与 WinRT 组件互操作

CLR #WinRT

C# 与 WinRT 组件互操作

在 Windows 平台开发中,WinRT(Windows Runtime)是一种现代组件模型,它统一了 C++、C#、VB.NET、JavaScript 等语言的互操作方式。而作为 .NET 开发者,我们需要知道如何 优雅地与 WinRT API 和组件交互
image.png


1. CLR 投影与 WinRT 类型系统规则

CLR Projection 就像一层“语言翻译”,让 WinRT API 在 C# 世界中表现得更自然。

  • 投影规则
    • WinRT 的 IVector<T> → .NET 的 IList<T>
    • WinRT 的 IMap<K,V> → .NET 的 IDictionary<K,V>
    • WinRT 的 IAsyncAction → .NET 的 Task
    • WinRT 的 IAsyncOperation<T> → .NET 的 Task<T>

👉 这样开发者几乎可以像用 .NET API 一样用 WinRT。

graph TD A[WinRT API] -->|Projection| B[CLR/.NET API] B --> C[".NET开发者调用 Task/IDictionary/IList"]

2. WinRT 类型系统核心概念

  • WinRT 类型系统是 基于 COM(组件对象模型) 的,但比传统 COM 友好得多。
  • 它只支持一些基础类型(int, string, bool, Guid, DateTime 等),不直接暴露复杂的 CLR 特性(比如 Nullable<T>)。
  • CLR 通过 类型适配 自动完成“对接”。

3. 框架投影(Framework Projections)

框架投影就是 .NET Framework / .NET Core 在背后做的“翻译”。

例如:

  • 当你调用 Windows.Storage.StorageFile.OpenAsync(),CLR 会自动把它投影成 Task<Stream>,这样用 await 即可。

4. 调用异步 WinRT API

WinRT 的异步 API 基本都是基于 IAsyncActionIAsyncOperation<T>,而在 C# 中我们直接用 async/await

示例(Unity 下 UWP 插件交互):

using System;
using System.Threading.Tasks;
using Windows.Storage;

public class WinRTInteropExample
{
    public async Task<string> ReadFileAsync(string fileName)
    {
        StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///{fileName}"));
        string text = await FileIO.ReadTextAsync(file);
        return text;
    }
}

在 Unity 的 UWP 导出项目中,你可以直接用 await 调 WinRT API,而不用关心底层 IAsyncOperation<T>


5. WinRT 流与 .NET 流互操作

  • WinRT 流:IRandomAccessStream
  • .NET 流:Stream

CLR 提供了适配器:

  • WindowsRuntimeStreamExtensions.AsStream()
  • WindowsRuntimeStreamExtensions.AsRandomAccessStream()
using Windows.Storage.Streams;
using System.IO;

IRandomAccessStream winrtStream = await file.OpenAsync(FileAccessMode.Read);
Stream dotNetStream = winrtStream.AsStream();

6. CLR 与 WinRT 间传递数据块

WinRT 常见的场景是 IBuffer,而在 .NET 中我们用 byte[]

转换方式:

  • IBuffer.AsStream()
  • WindowsRuntimeBufferExtensions.ToArray()

这样可以高效处理大块数据(比如视频帧、网络传输数据)。


7. 在 C# 中定义 WinRT 组件

不仅可以调用 WinRT API,还可以在 C# 中 编写 WinRT 组件,供其他语言(比如 C++/JavaScript)调用。

定义规则:

  • 只能使用 WinRT 支持的类型(不能直接用 Nullable<T>Tupledynamic)。
  • 类必须 public sealed

示例:

public sealed class MathHelper
{
    public int Add(int a, int b) => a + b;
}

这样编译后就能在 C++ 或 JS 中被调用。


总结

本章的核心一句话:
CLR Projection 是桥梁,帮我们在 C# 世界中“无痛”调用 WinRT API,而开发者几乎感知不到差异。

主要关注的几个实践点:

  1. 理解 CLR Projection 规则(异步/集合/流)。
  2. 学会 async/await 调 WinRT API。
  3. 知道如何在 C# 中定义 WinRT 组件供外部调用。

Unity 面试题(含解析)

Q1:Unity UWP 平台下,如何从 WinRT API 获取文件内容?

  • 答案:使用 StorageFile + FileIO.ReadTextAsync,在 C# 中用 await 调用。

Q2:WinRT 的 IAsyncOperation<T> 在 .NET 中映射成什么?

  • 答案:投影为 Task<T>,支持 await

Q3:在 Unity 中如何把 IRandomAccessStream 转换为 .NET Stream

  • 答案:使用 WindowsRuntimeStreamExtensions.AsStream()

Q4:能否在 Unity(C#)中定义 WinRT 组件并让 C++ 调用?

  • 答案:可以,类必须 public sealed,并且只使用 WinRT 支持的类型。

Q5:WinRT 与 .NET 在集合类型上的典型投影规则有哪些?

  • 答案
    • IVector<T>IList<T>
    • IMap<K,V>IDictionary<K,V>
    • IAsyncActionTask
posted @ 2025-08-26 10:08  世纪末の魔术师  阅读(27)  评论(0)    收藏  举报