2011-04-12 290 views
1

我写了一个泛型类,并希望从静态方法中创建它的实例。问题是我无法创建对象的通用实例。我知道这听起来很混乱,最好是展示代码。泛型类型的返回实例

public class Parameter<T> : IParameter<T> 
{ 
    public string Name { get; set; } 
    public T Value { get; set; } 

    public bool IsValid() 
    { 
     if (String.IsNullOrEmpty(Name)) 
      return false; 

     return (typeof(T) == typeof(String)) || 
       typeof(T) == typeof(bool) || 
       typeof(T) == typeof(int) || 
       typeof(T) == typeof(double); 
    } 

    public XElement ToXml() 
    { 
     if (!IsValid()) 
      throw new InvalidParameterException(); 

     var xElement = new XElement("Parameter", Value, 
            new XAttribute("Type", typeof (T)), 
            new XAttribute("Name", Name)); 
     return xElement; 
    } 

    public static Parameter<T> FromXml(XElement xElement) 
    { 
     var sType = xElement.Attributes() 
        .Where(attribute => attribute.Name == "Type") 
        .Single().Name.ToString(); 
     var name = xElement.Attributes() 
           .Where(attribute => attribute.Name == "Name") 
           .Single().Name.ToString(); 
     var sValue = xElement.Value;//need to use this 
     var typeVar = Type.GetType(sType);// and this to create proper instance of Parameter<T> 

     //I need somehow set T equal to typeVar here and Set 
     return new Parameter<T>() {Name = name};//this is wrong. 
     //I need return either Parameter<int> or Paramter<double> or Parameter<string> or Parameter<bool> 
     //basing on typeVar 
    } 
} 

我不确定这是否有可能...但看起来像它是微不足道的对象设计要求。有任何想法吗? 谢谢!

UPD:我正在使用.NET 4.0。它有什么区别? :)

UPD2:现在看问题,我看到这是一个愚蠢的问题。并且返回这样的“通用”对象是不可能的。

+0

这是完全不可能从方法内部设置'T'。想想:你怎么可能称这种方法? – SLaks 2011-04-12 16:30:29

+0

var parameter = Parameter.FromXml(element); ? :) – 2011-04-12 16:38:22

+0

ofcourse你可以潜入动态领域,但我不会潜入那一个快速;) – Polity 2011-04-12 16:41:06

回答

1

创建一个非泛型基类,并从中继承泛型类(它们可以具有相同的名称,只有泛型类型不同)。在非泛型基类上,在静态方法中创建泛型实例(它返回非泛型基类作为结果)。然后,您可以将其转换为您期望的泛型类型。

public abstract class Parameter { 
    public static Parameter FromXml(XElement xElement) { 
    ... 
    } 

    public string Name { get; set; } 

    public abstract XElement ToXml(); 
} 

public class Parameter<T>: Parameter { 
    public T Value { get; set; } 

    public override XElement ToXml() { 
    ... 
    } 
} 

是不是真的这样做,因为你的样品中被指定T类型的静态方法运行前的另一种方式。

+0

谢谢!我想过这个。鉴于我在使用.NET 4.0,你确定没有其他方法吗? – 2011-04-12 16:37:15

+0

是的,因为这会违反合约,无论使用哪个版本:在您的代码中,参数 .FromXml()*必须*返回一个参数,因为这是该方法的声明返回类型。 – Lucero 2011-04-12 16:39:04

0

这可以为自定义类工作,但它可能不适用于值类型。看看This Post看看这个工作对于堆类型。

+0

这与这个问题真的有关系吗? – Lucero 2011-04-12 16:40:20

0

正如SLak所示,这是不可能的。它认为这种方式,

Parameter<???> value = Parameter<???>.FromXml(...); 

你以后还怎么解决时,它依赖于的XmlElement的内容questionmarks应该是什么?

您应该使用一个公共类,它既捕获Value作为对象并公开类型信息。

1

问题是:T是在编译时评估的。编译器没有任何机会知道你的'Type'将在运行时评估哪个实际类型。另外,在编译的程序集中,不再存在泛型。因此,为了在运行时构建一个类型,根据只能在运行时进行评估的条件,您必须将编译器作为具体类型进行编译。所以,地方您可以在一个if ...这样的其他梯级决定你的返回类型:

if (sType is String) 
    return new Parameter<String>() 

else if (sType is double) 
    return new Parameter<double>() 
... 

这可以被放置在工厂类的内部或向右附近XElement类,我猜。 为了能够返回参数,例如,您可以使用一个接口(或者一个普通的基类,就像在另一个答案中一样),它可以代表所有参数变体。这就是为什么解析Xml IMO的方法更好地放置在Parameter之外的原因。

而且,因为它似乎,你是从证书XML“反序列化”的,可以考虑使用一些去/串行功能;)

+0

“另外,在编译后的程序集中,不再存在泛型。” - 我认为你正在将Java的删除与.NET(真正的)泛型混合在一起。在.NET中,每个泛型类型为用作类型参数的每个泛型类型组合形成一个不同的类型。你可以在运行时使用开放的泛型'Type'上的'MakeGenericType()'(例如在这个样例中'typeof(Parameter <>)。MakeGenericType(typeof(string))''在运行时产生与' typeof(参数)')。 – Lucero 2011-04-13 08:42:03