如何在不知道类型时指定类型变量

时间:2012-02-08 07:54:10

标签: c# oop generics

我的BusinessObject类有这个扩展方法:

public static class Extensions
{
    public static T Clone<T>(this T obj)
        where T: BusinessObject<T>, new()
    {
        T newObj = new T();
        var props = newObj.Properties;

        foreach (var p in props)
            newObj.Properties[p.Name].SetValue(newObj, obj.Properties[p.Name].GetValue(obj));

        return newObj;
    }
}

该方法的内容很有用,但我有一个非泛型的BusinessObject类和一个通用的对应类。我的很多代码都在非泛型变量中传递了对象的泛型版本的实例(请不要问我20个关于原因的问题)。我到目前为止没有遇到过问题,因为当我调用这个扩展方法时,它需要一个通用版本。

调用Clone方法的代码使用包含BusinessObject变量实例的BusinessObject变量。如何将变量转换为实际变量?换句话说:

Customer cust = new Customer();   // Customer derives from BusinessObject<Customer>
var CustomerClone = cust.Clone(); // This works

BusinessObject obj = cust;
var clone = obj.Clone(); // This doesn't work

现在当然在这个例子中我知道'obj'是一个Customer,但在我的实际方法中我不知道它可能是任意数量的派生类型。通过简单地使用GetType(),我可以很容易地找出派生类型是什么,但是如何在运行时将变量转换为该类型?

1 个答案:

答案 0 :(得分:2)

在您的情况下,我会说“丢失T” - 您没有使用任何其他方式无法完成的重要事项(例如Activator.CreateInstance)。您可以提供两个API - 一个是通用的,一个是非泛型的,以便于方便的转换。例如:

BusinessObject newObj = (BusinessObject)Activator.CreateInstance(obj.GetType());

这也很关键,因为您想要的T实际上不是声明 T,而是具体 T 。含义:如果您有SuperCustomer : Customer,但将其放在Customer变量中,然后调用Clone,则需要获得新的SuperCustomer。但是,T将是Customer。使用GetType()会更加可靠。

另一个有用的技巧是dynamic,这是一种从非泛型转向泛型的偷偷摸摸的方式。考虑:

dynamic foo = 123;
Bar(foo);

void Bar<T>(T bar) {
   Console.WriteLine(typeof(T));
}

将写System.Int32。尽管只是在编译器中真正了解Tobject主要实现为dynamic,并且有一些奇特的位),它已经在运行时翻转到正确的object

然而,要强调 - 我不会在这里使用它:我只会:

public static BusinessObject Clone(this BusinessObject obj)
{
    BusinessObject newObj = (BusinessObject)
          Activator.CreateInstance(obj.GetType());
    var props = newObj.Properties;

    foreach (var p in props)
        newObj.Properties[p.Name].SetValue(newObj,
          obj.Properties[p.Name].GetValue(obj));

    return newObj;
}
如果我真的需要泛型,那么dynamic作为我的后备策略。