【问题标题】:Avoiding boxing in generic blackboard避免在通用黑板上装箱
【发布时间】:2014-06-17 17:40:01
【问题描述】:

黑板是在运行时存储和获取通用键值对的对象。它可以通过Dictionary<object,object> 实现。一些子系统写入黑板以让其他子系统从中读取。

存储黑板的系统不知道里面是什么类型的物体,什么时候。特定键的写入者和读取者总是知道并同意键值对的类型。为了易于实现而牺牲了编译时检查 - 有许多编写者和阅读者,并且他们不断迭代。

我的黑板界面是这样的:

interface Blackboard {
    bool HasKey(object key);
    T GetValue<T>(object key);
}

编写者创建并返回黑板,因此SetValue(key, value) 可以是一个实现细节。

我最初的实现使用了Dictionary&lt;object,object&gt;,一切都很好。但是,这个黑板必须是快速且无分配的。这是没有商量余地的。如果作者将一个浮点值推入黑板,天真的实现将 int 装箱以放入字典中。

我不能在实现类BlackboardImpl&lt;ValueType&gt; : Blackboard 上使用泛型类型,因为值类型在黑板上不是恒定的。

我可以使用多个内部字典,Dictionary&lt;object,float&gt;Dictionary&lt;object,int&gt; 等,带有备用Dictionary&lt;object,object&gt;,以及许多 SetValue 函数,所以现在我不会在插入时装箱。但是由于GetValue函数来自于接口,所以我不能对其进行约束,所以我仍然在退出时装箱:

T GetValue<T>(object key) {
    if (typeof(T) == typeof(int)) {
        // return intStore[key]; // doesn't compile
        return (T)(object)intStore[key]; // boxes, allocates, bad.
    }
    // ...
}

我在这里是否缺少任何语法技巧,包括更改黑板界面以避免拳击?任何反射黑客都会违反“快速”要求,即使您可以在没有分配的情况下实现它。

干杯。

【问题讨论】:

  • @NicoSchertler:不,使用dynamic 肯定会装箱。
  • @JonSkeet:好的,我不确定。删除了评论。
  • 您可以尝试将void*unsafe 一起使用吗?

标签: c# generics


【解决方案1】:

虽然我不会想要这样做(而且我需要说服拳击的成本确实会很高),但您可以拥有多家商店并拥有一个变量在你的方法中输入Dictionary&lt;object, T&gt; - 我相信这样你就可以避免拳击:

T GetValue<T>(object key)
{
    Dictionary<object, T> store;
    if (typeof(T) == typeof(int)
    {
         store = (Dictionary<object, T>) (object) intStore;
    }
    else if (typeof(T) == typeof(float))
    {
        store = (Dictionary<object, T>) (object) floatStore;
    }

    // etc - with a default or an error case for unhandled types.
    return store[key];
}

请注意,这里的双重强制转换对于让编译器满意是必要的,但它涉及装箱。

【讨论】:

    【解决方案2】:

    我不建议将其用于生产代码,但使用未记录的 __makeref__refvalue 方法是将 T 视为不装箱的 int 的唯一方法

    static T GetValue<T>()
    {
        if (typeof(T) == typeof(int))
        {
            int i = intStore[key];
            T val = default(T);
    
            __refvalue(__makeref(val), int) = i;
            return val;
        }
        // ...
    
        return default(T);
    }
    

    更多:Why is TypedReference behind the scenes? It's so fast and safe… almost magical!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 2016-06-27
      相关资源
      最近更新 更多