2016-06-09 5 views
1

У меня есть базовый класс прототип:Как отбрасывать динамический тип при общей функции?

class CItemProto { 

    public var id:Int; 

    public var count:Int; 

    ... 
} 

и некоторые расширения различного рода:

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

... и так далее. Каждый экземпляр элемента имеет уникальный идентификатор, так что я могу хранить все свои вещи в одном классе инвентаризации с простым доступом IntMap:

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() аксессор с некоторым определенного товара, и этот тип элемента и если я ошибаюсь в выборе типа, метод должен вернуть null значение. Например:

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

Но это не работает. Простой небезопасный литье терпит неудачу, если я запрашиваю неправильный тип, безопасные литые запросы Динамический тип вместо общего T замена. Что делать, чтобы фильтровать запрошенные объекты по их типу? Я могу передать тип как второй аргумент, но он выглядит громоздким и чрезмерным.

ОБНОВЛЕНИЕ Я нашел тему How to look for a class type in an array using generics, поэтому мой вопрос не имеет смысла. Я передам желаемый тип в качестве второго аргумента.

ответ

1

Я хотел бы использовать что-то вроде этого:

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; 
} 

Тогда вы должны явного типа, что вы хотите, потому что это не то, что может быть решена compiletime. Типирование и тогда имеет смысл:

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

+0

Спасибо, я сделал то же самое решение. Теперь я вижу, что это не недостаток, чтобы передать класс как тип ожидаемых данных. – meps

+0

Вы можете использовать 'return Std.instance (v, c)' для замены 'if..return cast ... return null' – KevinResoL

-1

Я сделал один действительно уродливый обходной путь:

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); 

Но вы не должны делать, как это.

+1

Создание экземпляра, чтобы получить это класс? Зачем даже отправлять ответ, который заканчивается «Но вы не должны так делать». –

Смежные вопросы