首页 > 解决方案 > 使用 Unsafe.As 从标记接口转换为已知的泛型类型?

问题描述

我经常面临需要缓存通用泛型接口的对象但具有不同泛型类型的场景。

让我们考虑这个非常人为的例子(显然不完全是真实世界的用例):

// IInterface is effectively just use as a non-generic marker interface for...
interface IInterface
{ }

// ... This one here!
interface IInterface<T1, T2> : IInterface
{
    T1 DoSomething(T2 withB);
}

class TheCache
{
    private readonly Dictionary<IInterface, IInterface> _cache = new();

    public void Store<T1, T2>(IInterface<T1,T2> key, IInterface<T1, T2> value)
        => _cache[key] = value;

    private IInterface<T1, T2> Get<T1, T2>(IInterface<T1, T2> key)
    {
        // Can we use Unsafe.As safely here?
        return Unsafe.As<IInterface<T1, T2>>(_cache[key]);
    }
}

TheCache 确保类型一致性;我们知道_cache中的每一个key和value不仅仅是IInterface,实际上是IInterface<,>的一些通用表现。我们也知道 key 和 value 实例的泛型类型是相同的。

现在在 Get 函数中,我们知道检索到的值实际上是一个 IInterface<T1,T2>,但我们仍然需要转换它。一种“幼稚”的方式就是

    private IInterface<T1, T2> Get<T1, T2>(IInterface<T1, T2> key)
        => (IInterface<T1,T2>)_cache[key];

虽然效果很好,但我认为进行检查演员表会有(微小的)性能损失。

既然我们知道演员表会成功,我们可以应用任何未经检查的演员表吗?具体来说,

  1. 我们可以安全地使用 Unsafe.As<IInterface<T1,T2>>() 吗?我对 C# 接口调度不是 100% 坚定的;虽然我们知道结果将是 IInterface<T1,T2>() 的实例,但我不确定 C# 在(安全)将 IInterface 转换为 IInterface<T1,T2> 时是否通常需要进行任何转换,这不会出现不安全的演员表
  2. 可能不会,但以防万一:如果 _cache 是 Dictionary<object,object> 而不是 Dictionary<IInterface, IInterface>,这个问题的答案会改变吗?

标签: c#unsafe

解决方案


推荐阅读