2011-10-23 125 views
0

可以說我有一個泛型類:找出一個泛型類的類型

class Foo { 
// protected Type t; 

// public void SetT(string strval) { 
//  ((Foo<t>)this).Set(strval); 
// } 
} 

class Foo<T> : Foo { 
    private T val; 

    public void Set(string strval) { 
     if (this is Foo<float>) { 
      this.val = float.Parse(strval); 
     } else if (this is Foo<int>) { 
      this.val = int.Parse(strval); 
     } 
    } 
} 

現在我創建一個對象,並把它放在一個ArrayList:

ArrayList a = new ArrayList(); 
a.Append(new Foo<float>); 

然後我忘了類型Foo <>。現在,我該如何設置?我嘗試了明顯的候選人:

(Foo)a[0].Set("5.0"); 
(Foo<a[0].GetType()>)a[0].Set("5.0"); 

但那些失敗。

有沒有一種方法,我可以調用該方法沒有明確知道Foo的類型<>?

如果沒有,我可以以某種方式將Foo類型保存到Foo.t中,然後取消註釋並使用Foo.SetT?

啊,仿製藥。很不錯的工具,如果你知道如何使用它們:-)

問候, dijxtra

+0

有沒有在這裏使用泛型一個特別的原因? – Gabe

回答

3

絕對沒有理由在這裏使用泛型。當您要執行的操作類型是通用時,將使用泛型。換句話說,他們是獨立於他們被執行的類型。您正在做相反的操作:不同取決於類型。

鑑於這種情況,你應該刪除泛型參數,使Set()Fooabstract,並從中獲得相應的類來處理不同的類型:

abstract class Foo 
{ 
    public abstract void Set(string value); 
} 

class FooDouble : Foo 
{ 
    double val; 
    public override void Set(string value) 
    { 
     this.val = double.Parse(value); 
    } 
} 

// Etc. 

然後,你應該存儲你Foo S IN一個List<T>

List<Foo> fooList = new List<Foo>(); 
fooList.Add(new FooDouble()); 

後來,你可以這樣說:

fooList[0].Set("5.0"); 

它只會工作!不需要記住!

+0

很多很好的答案,但是這個最清楚地告訴我我做錯了什麼。謝謝! – dijxtra

4

的一種方法是使你的通用Foo類實現一個接口:

interface IFoo { 
    void Set(string strval); 
} 

class Foo<T> : IFoo { 
    private T val; 

    public void Set(string strval) { 
     ... 
    } 
} 

然後你就可以轉換爲IFoo並調用Set()

((IFoo)a[0]).Set("5.0"); 
+0

這是有效的答案。 但是,如果您對如何獲得泛型類型感興趣,可以這樣做: typeof(Foo <>)。MakeGenericType(typeof(float)); –

+0

@David他仍然需要'Set()'內的開關邏輯,這幾乎無法在這裏使用泛型的目的。 – dlev

+0

問題不在於泛型是否適用於這種特殊情況,而是如何在不知道類型時使用泛型類。 –

3

你想覆蓋的012執行在派生類中。

class Foo { 
    public virtual void Set(string val); 
} 
class Foo<T> : Foo { 
    public override void Set(string val); 
} 
+0

+1,儘管OP也應該使用'List ',而不是'ArrayList'。 –

+0

@Jimmy覆蓋是有道理的,但泛型不適用。 'Set()'方法仍然需要打開'T'類型,這在很大程度上違背了泛型的目的。 – dlev

1

除了什麼吉米指出您的基類,你可以使用泛型集合而不是ArrayList和使用一個類型的轉換器:

public interface IFoo 
{ 
    void Set(string value); 
} 

public class Foo<T> : IFoo 
{ 
    private T val; 

    public void Set(string value) 
    { 
     var typeConverter = TypeDescriptor.GetConverter(typeof(T)); 

     if(typeConverter.CanConvertFrom(typeof(string))) 
     { 
      val = (T)typeConverter.ConvertFromString(value); 
     } 
     else 
     { 
      throw new InvalidOperationException(); 
     } 
    } 
} 

以上將與工作,要麼您的ArrayList:

ArrayList a = new ArrayList(); 
a.Append(new Foo<float>()); 

((IFoo)a[0]).Set("123.4"); 

或者與類型的集合:

List<IFoo> list = new List<IFoo>(); 
list.Add(new Foo<float>()); 

list[0].Set("123.4"); 

作爲額外的好處,您不需要在Set方法中擁有if聲明並嘗試考慮所有可能的類型。

+0

這是非常甜蜜的解決方案。它實際上是通用的! – dlev

0

如果您想知道泛型中使用的類型參數,請使用GetGenericArguments方法。

class Foo<T> { 
    int input_as_int; 
    float input_as_float; 


    public void Set(string strval) { 
     if (this.GetType().GetGenericArguments().First() == typeof(float)) { 
      this.input_as_float = float.Parse(strval); 
     } else if (this.GetType().GetGenericArguments().First() == typeof(int)) { 
      this.input_as_int = int.Parse(strval); 
     } 
     // Else .. throw an exception? return default value? return 0? what makes sense to your application 
    } 

或者,也可以通過完全傳遞接口並在構造函數中傳遞輸入字符串。

public class Foo<T> 
{ 
    public Foo (string input) 
    { 
     var typeConverter = TypeDescriptor.GetConverter(typeof(T)); 

     if (typeConverter.CanConvertFrom(typeof(string))) 
     { 
      Value = (T)typeConverter.ConvertFromString(input); 
     } 
     else 
     { 
      throw new InvalidOperationException(); 
     } 
    } 

    public T Value { get; set; 
    } 
} 

然後你就可以像這樣使用它。

var test = new List<int> Foo ("3"); 
0
using System; 
using System.Collections; 
using System.Collections.Generic; 

class Foo { 
} 

class Foo<T> : Foo { 
    private T val; 

    public void Set(string strval) { 
     var _type = typeof(T); 
     val = (T)(_type.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, null, new Object[] { strval })); 
    } 
    override public string ToString(){ 
     return String.Format("{0}", val); 
    } 
} 
class Sample { 
    static void Main(string[] args){ 
     ArrayList a = new ArrayList(); 
     a.Add(new Foo<float>()); 
     a.Add(new Foo<int>()); 

     dynamic ax = a[0]; 
     ax.Set("5.5"); 
     ax = a[1]; 
     ax.Set("55"); 
//EDIT 
//But I may have to set the float value to Foo <int> If you forgot 
//  ((Foo<float>)a[0]).Set("5.5"); 
//  ((Foo<int>)a[1]).Set("55"); 
     Console.WriteLine("{0},{1}", a[0], a[1]); 
    } 
}