2016-11-10 6 views
2

注:この質問は、列挙型よりもジェネリックについてです。最初に一致する列挙型からenum定数を取得する方法

私はいくつかの列挙型を持っており、すべて共通のインターフェイスIEffectを実装しています。

enum ElementalEffect implements IEffect { 
    FIRE, WATER; 
} 
enum CombatEffect implements IEffect { 
    PARALYSIS, SLEEP; 
} 

例えば

私は武器にエフェクトを追加する必要があります設定ファイルを、解析したいと思います。そのためには、特定の名前をその効果の1つに解決する必要があります。維持するために、それをシンプルに保つために、私はこのような方法を書いて考える(主に擬似コード、これはコンパイルされません実際には疑問の点は、このコンパイルを作成する方法です。):今

IEffect resolveEffectName(String name, Class... clazzes) { 
    for(Class clazz : clazzes) { 
     try { 
      return Enum.valueOf(clazz, name); 
     } catch(IllegalArgumentException) { /* ignore, try next class */} 
    } 
    throw new IllegalArgumentException("No matching effect found for " + name); 
} 
// resolveEffectName(readNameFromFile, ElementalEffect.class, CombatEffect.class); 

私が持っている問題は、私は...列挙型が引数には適用されません型の方法valueOf(Class<T>, String)を私に言っ

コンパイラせずにそのメソッドを記述する方法を見つけ出すことができないということです


人々は、これが動作しない

private static ICombatEffectType getFirstResolved(String name, Class<? extends Enum<?>>... classes) { 
    for (Class<? extends Enum<?>> clazz : classes) { 
     try { 
      return Enum.valueOf(clazz, name); 
     } catch (IllegalArgumentException e) { 
     } 
    } 
    return null; 
} 

それがあるべきと述べました。試してみてください(あなたが私を信じていない場合)。

Enum型のメソッドvalueOf(Class<T>, String)はあなたの最初の方法を使用して、引数(Class<capture#6-of ? extends Enum<?>>, String)

+1

'Class <? extends Enum > ... clazzes' –

+0

クラスの '? 'とネストされたEnumのキャプチャは異なるがEnum.valueOfを呼び出すためには同じでなければならないので、これは機能しない – WorldSEnder

+0

Hm 、真実。しかし、タイプセーフな方法でこれを書くのに問題がある場合は、まったく別のアプローチを見つける必要があるかもしれないと考えてください。 –

答えて

2

それはあなたのスタイルだ場合は、流暢にこれを書くことができます。

その後
class FluentGetter { 
    private final String name; 
    private IEffect found; 

    FluentGetter(String name) { this.name = name; } 

    <T extends Enum<T> & IEffect> FluentGetter search(Class<T> clazz) { 
    if (found == null) { // If you've already found something, don't overwrite that. 
     try { 
     found = Enum.valueOf(clazz, name); 
     } catch (IllegalArgumentException e) {} 
    } 
    return this; 
    } 

    IEffect get() { 
    return found; // + check if it's null, if you want. 
    } 
} 

IEffect effect = 
    new FluentGetter(name) 
     .search(ElementalEffect.class) 
     .search(CombatEffect.class) 
     .get(); 

これにより、それぞれのクラスに対して別々のメソッド呼び出しを行うことで、クラスの配列の汎用的な境界の問題を回避できます。

私はこれを自分では使用しません。ちょうどオプションとしてそれを投げる。

+0

私はそれが好きです。特定の*アイテムタイプ*に対して可能なすべてのエフェクトクラスのみが有効になるので、これでほんの数個のエフェクトクラスが本当に簡単に検索されます – WorldSEnder

0

これは(警告を)コンパイルする必要がありますには適用されません:あなたは本当に欲しい

return (IEffect) Enum.valueOf((Class<Enum>) clazz, name); 
1

列挙型の名前のマップです。ストリームを使用して簡単に作成できます。

private static final Map<String, IEffect> constants 
    = Stream.of(ElementalEffect.values(), CombatEffect.values()) 
     .flatMap(Arrays::stream) 
     .collect(Collectors.toMap(Enum::name, Function.identity())); 

IEffect resolveEffectName(String name) { 
    if(!constants.containsKey(name)) 
     throw new IllegalArgumentException("No matching effect found for " + name); 

    return constants.get(name); 
} 
+0

もちろん、 'clazzes'の中で一つの値だけを渡すことはできますか? –

+0

@AndyTurnerあなたが正しいです、私は配列の共分散が十分であると思いました。うーん、今私は自分自身を混乱させるだけです。 –

+0

最初の方法は機能しません。すべてのenum-classで同じ型のバインドが必要なためです。しかし、あなたの2番目の点については正しいです、私はマッピングを事前計算し、名前を正規化する必要があります – WorldSEnder

1

私はラッパークラスを使用して警告なしにすべての仕事を作るための方法を見つけました:

private static class Wrapper<T extends Enum<T> & IEffect> { 
    private Class<T> clazz; 

    public Wrapper(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    public IEffect resolveName(String name) { 
     return Enum.valueOf(clazz, name); 
    } 
} 
private static IEffect getFirstResolved(String name, Wrapper<?>... clazzes) { 
    for (Wrapper<?> clazz : clazzes) { 
     try { 
      return clazz.resolveName(name); 
     } catch (IllegalArgumentException e) {} 
    } 
    throw new IllegalArgumentException("No enum has a member " + name); 
} 

// Example call 
ICombatEffectType elemental = getFirstResolved(
      type, 
      new Wrapper<>(ElementalType.class), 
      new Wrapper<>(StatusEffect.class)); 
+0

良い方法ですが、私はラッパーが役に立たないと思う。正しく入力しても警告の問題はないはずですが、それを持っていても、それを処理するためにデザインを複雑化するのは残念です – davidxxx

+0

ラッパーは 'Class <? extends Enum > '2つの匿名のキャプチャは同じです(そのクラスでEnum#valueOfを呼び出せるようにするために必要です) – WorldSEnder

関連する問題