2016-09-19 6 views
0

私は単純なObjectPoolを実装しています。 ObjectPoolは、ObjectPoolObjectのスタックを保持します。 ObjectPoolObjectは、2つのメソッドを定義する抽象クラスです。親プールへの参照をObjectPoolObjectクラスに追加しようとしています。私は不思議な繰り返しのテンプレートパターンを使用して作業する必要がありますが、私はすでにObjectPoolObjectから派生したクラスから派生することができませんでした。 (つまり、手榴弾はObjectPoolObjectから継承した弾丸を継承します)...`ObjectPool 'を` ObjectPool <ObjectPoolObject>'に変換できません

とにかく、親プールはObjectPoolObjectによって保持されています。ObjectPool m_parent ...しかし、私はm_parent = thisを設定することはできません。 ObjectPoolクラスで...私は間違いなくできるはずです。 T以来

public abstract class ObjectPoolObject : MonoBehaviour { 
    public abstract void ObjectPool_Activate(); 
    public abstract void ObjectPool_Deactivate(); 

    public ObjectPool<ObjectPoolObject> m_pool; 
} 


public class ObjectPool<T> where T : ObjectPoolObject 
{ 
    public ObjectPool(CreateObjectDelegate creationMethod) 
    { 
     m_creationMethod = creationMethod; 
     T objectPoolObject = creationMethod(); 
     // this is the line that gives me error CS0030: Cannot convert type `ObjectPool<T>' to `ObjectPool<ObjectPoolObject>' 
     objectPoolObject.m_pool = this; 
    } 
} 

:私は、私は安全にこれを行うことができるはずのようにそれはそう...オブジェクト、その後ObjectPoolにキャストするキャストする必要がありますする必要はいけないObjectPoolObject私はこれを行うことができるはず...

私が必要とするのは、ObjectPoolObjectがその親ObjectPoolへの参照を持つことです。これをどのように達成できますか?

EDIT:

error CS0030: Cannot convert type ObjectPool<T> to ObjectPool<ObjectPoolObject>' 

が、T以降:

これはエラーメッセージですObjectPoolObjectこれを行うことができるはずのようにそれはそう。そのような "子クラスを親クラスに変換することはできません..." TはObjectPoolObjectから継承...したがって、TのObjectPoolは、ObjectPoolObjectの子クラスObjectPoolに似ています... Liskov置換原則は、 TのObjectPoolからObjectPoolObjectのObjectPoolに移動します。

たとえば、BulletがObjectPoolObjectから継承するBulletのObjectPoolがあります。 ObjectPoolObjectsのすべての要素がObjectPoolObjectsであることを考慮して、ObjectPoolObjectsのObjectPoolにキャストする必要があります。

EDIT - キャストの問題が何であるか理解し始めています....説明するのがとても難しい、うわー。

EDIT2 - ジェネリック型の "in"キーワードを使用してインターフェイスを定義する答えは、この問題に対する正解です。しかしながら!私はこれが "複雑すぎる"という行を超え、ObjectPoolObjectからm_poolフィールドを削除することに決めました。オブジェクトプールからオブジェクトを取得するときは、それがどのプールから来たのかを記録し、適切に戻すことができます。 m_poolフィールドは私のシステムをあまりにも汚くしすぎて、それを含めて正当化することができませんでした。

ObjectPoolからGenericismを完全に削除することも機能的な解決策ですが、すべてのObjectPool.Get呼び出しの戻り値をキャストする必要があります。

+0

いいえ、Tは、である(又はから継承)ObjectpoolObjectこれはここで、T ObjectPool あるObjectPoolが ObjectPool Shazi

+0

(またはから継承する)ことを意味するものではないという理由だけで:ObjectPoolObject .... これをObjectPool にキャストすることができるはずです... 私はあなたの文の第2部分が後方にあると思います。私はTがObjectPoolObjectです... –

+0

私はそうは思わない? ObjectPool であるm_poolに、ObjectPool という変数を割り当てようとしています(TはObjectPoolObjectから継承しています)。 また、TはObjectPoolObjectから継承していませんが、ObjectPool はObjectPoolから継承しています(m_poolを割り当てようとしているので仮定しているためです) – Shazi

答えて

2

hereと記載されているように、C#の共分散と反共分散を調べる必要があります。要するに

- あなたは問題がTが実際にObjectPoolObject、ObjectPool < T天気をObjectPool <ObjectPoolObject>から>継承を行うために、そのHOS何も継承しないながらということである

public class ObjectPool<**in** T> where T : ObjectPoolObject 
0

として、あなたのクラスを宣言する必要があります。

例えば、次のコードを取る:あなたが何をしようとして行うには

public class Class1<T> where T : Class3, new() 
{ 
    public Class1() 
    { 
     Class3 variable1; 
     variable1 = new T(); // This works just fine T is or inherits from Class3 

     Class1<Class3> variable3; 
     variable3 = new Class1<Class2>(); // This will not work, while Class2 does indeed inherit from Class3, 
              // Class1<Class2> is still a different class from Class1<Class3> 
              // while their type parameters have an inheritance between them, they themselves do not. 

     Class1<Class3> variable2; 
     variable2 = new Class1<T>(); // And for just the same reason as stated above, this will not work either 
    } 
} 

を、私たちは何かをより複雑にしなければならない(と正直に言うと、複雑さは常に良いことではありません)。しかし、ちょうどそれのために、このを見て:

public class AbstractObjectPool<T, T2> where T : AbstractObjectPool<T, T2> where T2 : ObjectPoolObject<T, T2> 
{ 
    public T m_pool; 
} 

public class ObjectPool<T> : AbstractObjectPool<ObjectPool<T>, T> where T : ObjectPoolObject<ObjectPool<T>, T> 
{ 
    public ObjectPool(Func<ObjectPool<T>> creationMethod) 
    { 
     ObjectPool<T> objectPoolObject = creationMethod(); 
     objectPoolObject.m_pool = this; 
    } 
} 

public abstract class ObjectPoolObject<T, T2> where T : AbstractObjectPool<T, T2> where T2 : ObjectPoolObject<T, T2> 
{ 

} 

(あなたのケースで)あなたは、単純な基本クラスのalltogeatherジェネリックをスキップしたほうが良いと共同ではないでしょうしかし、私は疑問に思う:

public class ObjectPool 
{ 
    public ObjectPool(Func<ObjectPoolObject> creationMethod) 
    { 
     ObjectPoolObject objectPoolObject = creationMethod(); 
     objectPoolObject.m_pool = this; 
    } 
} 

public abstract class ObjectPoolObject 
{ 
    public ObjectPool m_pool; 
} 
+0

ねえ、答えてくれてありがとう。私はObjectPoolのGenericを非常に便利な方法で使用しています。親のリファレンスを得るために便利さを変えることができると思います... 答えは基本的に次のようなものです。 "//これはできませんclass2は実際にClass3から継承しますが、 // Class1 はClass1とはまだ異なるクラスです //型パラメータには継承がありますが、それら自体は継承しません。 理由を理解できたら助かりますか? –

+0

私はObjectPoolクラスでジェネリックスを使用することから離れると思います.... –

+1

理由:コンパイラがClass1 およびClass1 のコードをJITすると、共有されない2つの異なるタイプが生成されます(Class1ForClass2とClass1ForClass3という名前の2つのクラスを手動で作成した場合のようなものです)。この場合、Class1ForClass3がClass1ForClass2との間でキャスト可能である理由がないことが容易にわかります。 しかし、これらの2つのクラスの間のコードは、JIT、つまり同じコード、異なるタイプで共有されます。 – Kolichikov

3

in修飾子を使用して、型パラメータを反変化させる必要があります。この修飾子は、インターフェイスとデリゲートでのみ使用できます。

interface IObjectPool<in T> where T : ObjectPoolObject 
{ 

} 

class ObjectPoolObject 
{ 
    public IObjectPool<ObjectPoolObject> Pool { get; internal set; } 
} 

class ObjectPool<T> : IObjectPool<T> where T : ObjectPoolObject 
{ 
    public ObjectPool(Func<T> createObject) 
    { 
     T obj = createObject(); 
     obj.Pool = this; 
    } 
} 
+0

AWESOME!ありがとうございました!私はそれが実行可能であることを知っていた。私は "out"キーワードではなく "in"キーワードが必要です。なぜなら、Tをパラメータとするインタフェースの "Store"メソッドが必要なので –

関連する問題