2016-09-21 2 views
-2
class Bar 
{ 
    static public Bar Instance { get { return null; /*return instance*/ } } 
} 

private void Foo<T>() where T : Bar 
{ 
    T getInstace = T.Instance; 
} 

これはエラーですが、インスタンスを取得する必要があります。C#Genericsでこれは不可能ですか?

これには解決策がありますか?

は、私はあなたが知っている、これをやっているしたいと思います

++

class Bar<T> 
{ 
    static public T Instance { get { return default(T); /*return instance*/ } } 
} 

class BarChild : Bar<BarChild> 
{ 
    public void Func(){} 
} 

private T Foo<T>() where T : Bar<T> 
{ 
    return T.Instance; 
} 

private void Example() 
{ 
    Foo<BarChild>().Func(); 
} 

に感謝します。 しかし、 "T.Instance"はエラーです。

+0

ポイントは何ですか? 'Foo'にパラメータを渡さないので、' Foo () 'と' Foo(Bar.Instance) 'の違いは最小です。 – dasblinkenlight

+0

Tタイプを渡すのはなぜですか?または、いくつかの工場の方法がありますか? –

+0

すべての型 'T'に有効な' Instance'の有効な型はありません。 'バー'は一般的である必要があります。あなたが望むものは完全にはっきりしていませんが、他の選択肢があるかもしれません。 – Rob

答えて

0

あなたは実際にあなたが望むことに近いです。これは型システムの濫用であると考える人もいます。私はそれを言語の弱点と考えています。解決しようとする問題は、タイプがハードコードされたタイプではなく、クラスのタイプである汎用クラスの静的メンバーにアクセスしたいということです。このです。

class Base<T> where T : Base<T> { 
    public static T SomeMethod() { ... } 
} 

class Derived : Base<Derived> { 

} 

public void Main() { 
    Derived d = Derived.SomeMethod(); // correctly returns an object of type Derived, even though method is defined in base class 
} 

これはC++のCRTPのバリエーションです。

これは実際には仮想ディスパッチまたはダイナミックディスパッチではありません。静的にこの動作を得る唯一の理由は、ジェネリックのためです。型はすべてコンパイル時に知られています。派生型が派生した型のメソッドであるかのように基本型のメソッドを使用できるようにするクラス階層では、これは依然として有効です。別の言い方をすれば、そこで宣言されているかのように、派生クラスで動作する基本クラスのテンプレート化されたメソッドを作ることができます。使用したい場所は、正しいタイプを返すClone()メソッドです。あなたは基本クラスのpublic abstract T Clone()と宣言することができ、それは派生クラスで正しい戻り値の型を持つでしょう。

EDIT:OPが望むすべてを行うために更新されたコード:

public class Base<T> 
    where T : Base<T>, new() { 
    public static T Instance { 
     get { 
      return new T(); 
     } 
    } 
} 

public class Derived : Base<Derived> { 
    public void SomeFunc() { 
     Console.WriteLine("SomeFunc()"); 
    } 
} 

// in other code 

private T Foo<T>() where T : Base<T>, new() { 
    // note that we can't just use T directly here, but that's okay, because we know that T is always going to be at least a Base<T> 
    return Base<T>.Instance; 
} 

private void Example() { 
    // the type of Base<Derived>.Instance is Derived, so you can call Func() on it 
    Base<Derived>.Instance.SomeFunc(); 

    // can also do this: 
    Foo<Derived>().SomeFunc(); 
} 
+0

私はFooの必要性があります().Func(); しかし、できません。 – Lim

+0

@リム:あなたが何を求めているのか分かりません。あなたはもう少し説明できますか? – siride

+0

@@ siride //フー()に電話したかっただけです。 Func();しかしT.Instance;コンパイルエラーのために使用することはできませんでした。私はリフレクションを行う方法を知ったので、私はそれを解決しました。答えてくれてありがとう。 – Lim

0

私はこれがstaticキーワードの根本的な誤解になると思います。これは、インスタンス間でメンバを共有するためのメカニズムではなく、メンバを静的に割り当てることができることをコンパイラに通知する方法です。つまり、実行時にプログラムの動的な動作に関係なく静的に割り当てることができます。

staticメンバーをvirtualにすることはできません。つまり、サブクラスでオーバーライドすることはできません。サブクラス化は静的なプロセスなので、継承されているかのように、親クラスの静的メンバーを参照することができます。これは、コンパイラがメンバーが定義されている場所を調べることができるからです。

文法上合法であっても、T.InstanceBar.Instance以外のものを参照する方法はありません。

+1

"インスタンス間でメンバを共有するメカニズムではありません" --- WAT – zerkms

+1

'static'キーワードは、C#のクラスの前に日付が戻っています。それは、この目的を非常にうまく果たすように起こりますが、それはその主な目的ではありません。 –

+0

プログラミング言語の主な目的は、「静的に何かを割り当てることができるバイナリを生成する」だけでなく、タスクを解決するための機能を提供することです。ランタイムが静的メンバーをオンデマンドで割り当てるという事実があなたの主張を証明するかどうかは不明です。 – zerkms

関連する問題