2011-10-23 93 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]); 
    } 
}