如何在泛型函数中转换为动态类型?

How to cast to dynamic type at generic function?

我有一个基本原型class:

class CItemProto {

    public var id:Int;

    public var count:Int;

    ...
}

和一些不同类型的扩展:

class CItemThing extends CItemProto { ... }
class CItemResource extends CItemProto { ... }
class CItemRecipe extends CItemProto { ... }

...等等。项目的每个实例都有唯一的 ID,所以我可以通过简单的 IntMap 访问将我所有的东西存储在一个库存中 class:

class CInventory {

    var mMap:IntMap<CItemProto>;

    public function new() {
        mMap = new IntMap();
    }

    public inline function set(item:CItemProto) { mMap.set(item.id, item); }

    public function get<T:CItemProto>(id:Int):T {
        var item = mMap.get(aId);
        if (Std.is(item, Class<T>)) // it doesn't work saying Unexpected )
            return cast item;
        return null;
    }

}

我的观点是使用 get() 访问器和一些项目 ID 和这个项目类型,如果我在类型选择上有误,方法应该 return null 值。例如:

// should return instance of CItemThing if it exists or null in the other way
var thing:CItemThing = inventory.get(123);

但是没有用。如果我请求错误的类型,简单的不安全转换会失败,安全转换需要 Dynamic 类型而不是通用的 T 替换。我应该怎么做才能按类型过滤请求的项目?因为我可以将类型作为第二个参数传递,但它看起来笨重且过多。

UPDATE 我找到了主题 How to look for a class type in an array using generics 所以我的问题没有意义。我将传递所需的类型作为第二个参数。

我做了一个非常丑陋的解决方法:

typedef Constructible = {
    function new():Void;
}

@:generic
public function get<T:(CItemProto,Constructible)>(id:Int):Null<T> {
    var typed = new T();
    var item:CItemProto = mMap.get(id);
    if (Std.is(item, Type.getClass(typed)))
        return cast item;
    return null;
}

现在我可以请求任何类型的项目,例如:

var thing:CItemThing = inventory.get(111);
var resource:CItemResource = inventory.get(222);

但你不应该这样做。

我会用这样的东西:

public function safeGetAs<T:CItemProto>(id:Int, c:Class<T>):T {
    var v = mMap.get(id);
    if (Std.is(v, c)) return cast v;
    return null;
}

然后你必须显式键入你想要的内容,因为这不是编译时可以解决的问题。打字也更有意义:

inventory.set(new CItemThing(1));
inventory.set(new CItemResource(2));

var a = inventory.safeGetAs(1, CItemThing);
trace(a); // returns instance
$type(a); // expected: CItemThing. is: CItemThing. 

var b = inventory.safeGetAs(2, CItemThing);
trace(b); // returns null
$type(b); // expected: CItemThing. is: CItemResource. 

演示:http://try.haxe.org/#65792