c# - 不知道类型时如何指定类型化变量

标签 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'是一个客户,但在我的实际方法中我不知道,因为它可能是任意数量的派生类型。我可以通过简单地使用 GetType() 很容易地找出派生类型是什么,但是我如何在运行时将变量转换为该类型?

最佳答案

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

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

这也很关键,因为你要的T其实不是declaration T,而是concrete T。意思是:如果你有一个 SuperCustomer : Customer,但是把它放在一个 Customer 变量中,然后调用 Clone,你想得到一个新的 super 客户。但是,T 将是 Customer。使用 GetType() 会更可靠。

这里另一个有用的技巧是dynamic,这是一种从非通用到通用的偷偷摸摸的方式。考虑:

dynamic foo = 123;
Bar(foo);

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

将写入 System.Int32。尽管在编译器中只真正了解 object(dynamic 主要实现为 对象,带有一些花哨的位)。

但是,要强调的是——我不会在这里使用它:我只会:

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 作为我的后备策略。

关于c# - 不知道类型时如何指定类型化变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9189509/

相关文章:

c# - 如何保护 Web API 上的 Controller 仅供本地计算机使用

c# - 如何隐藏实现

c# - 将语句与泛型一起使用 : using ISet<> = System. Collections.Generic.ISet<>

c# - 使用接口(interface)和通用约束进行类型推断

c# - 在 C# 中实现通用数据结构时避免徘徊

javascript - Angularjs 应用程序无法从 Wcf 服务返回消息

c# - 这个正则表达式是什么意思

c# - 如何在(rdlc)报告中水平显示表格

oop - 为什么面向对象中的方法是 "private"?

java - Java 中的类和继承——我做错了什么?