转换没有特定类型的泛型类

时间:2011-01-04 14:49:44

标签: c# .net generics casting

我有以下通用类

public class Home<T> where T : Class
{
   public string GetClassType
   {
       get{ return T.ToString() }
   }
}

现在,我得到一个对象X,我肯定知道它是Home:

public void DoSomething(object x)
{
    if(x is // Check if Home<>)
    {
        // I want to invoke GetClassType method of x  
        // but I don't know his generic type
        x as Home<?> // What should I use here?
    }
}

我是否可以在不指定类的泛型类型的情况下进行转换?

5 个答案:

答案 0 :(得分:9)

如果您确定DoSomething的参数是Home<T>,为什么不将其作为通用方法?

public void DoSomething<T>(Home<T> home)
{
   ...
}

当然,如果DoSomething在逻辑上应该是Home<T>上的实例方法,那就更容易了。

如果确实想要坚持使用你拥有的东西,你可以使用反射(未经测试):

public void DoSomething(object x)
{
    // null checks here.

    Type t = x.GetType();

    if (t.IsGenericType &&
          && t.GetGenericTypeDefinition() == typeof(Home<>))
    {
        string result = (string) t.GetProperty("GetClassType")
                                  .GetValue(x, null);

        Console.WriteLine(result);
    }

    else 
    {
        ... // do nothing / throw etc.
    }
}

答案 1 :(得分:4)

如果Home派生自基类怎么办?

public class Home
{
    public virtual string GetClassType { get; }
}
public class Home<T> : Home
    where T : class
{
    public override string GetClassType
    {
        get{ return T.ToString() } 
    }
    ...
}

然后

public void DoSomething(object x)
{
    if(x is Home)
    {
        string ct = ((Home)x).GetClassType;
        ...
    }
}

答案 2 :(得分:1)

如何使函数通用?

public void DoSomething<T>(object x)
{
    if(x is Home<T>)
    {
        x as Home<T> ...
    }
}

编辑: 另一种可能性是创建一个包含属性GetClassName的接口,因此您只需要检查它是否属于该接口。

public interface IDescribeClass
{
    public string GetClassName { get; set; }
}

BTW:我会使用完全限定名称

public string ClassType
{
    get{ return typeof(T).FullName; }
}

答案 3 :(得分:0)

您是否尝试过将方法定义更改为此类内容?

public void DoSomething<T>(Home<T> x)
{

}

答案 4 :(得分:0)

我知道这是一个旧主题,但是到目前为止,所有发布的答案都没有直接解决此问题,而只是建议的解决方法(即“使用反射”,“使DoSomething()方法通用”或“创建非-通用基类并调用此基类的“方法”)。

  

是否可以在不指定类的泛型类型的情况下进行转换?

因此要明确回答您的问题:否。由于C#中的covariance constraints,您不能转换为通用类。

更详细:我假设您想使用x as Home<object>作为最低的公共分母,以便能够调用toString()类提供的Object。将您的object x强制转换为Home<object>会需要协方差,而对于类而言,这是不可能的(只有通用接口和委托可以是协方差)。尽管这对prevent mistakes at compile time来说是很棒的,但是当您想要访问通用类上的方法时,确实很烦人。就“投射”而言,@ n8wrl答案可能是您最好的选择。

话虽如此,您还可以使用T参数上的out flag来寻求基于接口的解决方案:

interface IHome<out T> {
  string GetClassType { get; }
}

public class Home<T> : IHome<T> where T : class
{
  public string GetClassType
  {
      get { return typeof(T).Name; }
  }
}

然后这应该工作:

public void DoSomething(object x)
{
    if(x is // Check if Home<>)
    {
        var y = x as IHome<object>;
        var z = y.GetClassType;
    }
}