通过强制转换重用相同的函数,或者键入不同的对象类型

时间:2017-07-20 14:25:55

标签: c# .net casting polymorphism duck-typing

在.NET应用程序中,我正在使用两个远程WCF服务,这两个服务都具有“相同”对象的定义:CoreService.CustomerProductService.Customer

故意将“同一”加入引号;从命名空间的角度看,它们是两个不同的实体但是,由于生成/使用服务的方式,这是纯粹的。在这种情况下,两个对象都来自后端系统中的同一个库,这是一个给定的事实。

在特定场景中,我需要从两种对象类型中提取内容。我有一个函数,最初是为一个特定的实例构建的:

private static string _ExtractFoo(CoreService.Customer customer) {
    // removed for the sake of brevity
    return string.Empty;
}

我想要的实际上是重用相同的操作,通过提供重载和通过投射或装箱的方式简单地试图说服编译器和运行时这将只是工作(如果你愿意的话,简单地想一下duck typing )。

以下情况不起作用:

private static string _ExtractFoo(ProductService.Customer customer) {

    // #1 - Cast, results in error:
    //      Cannot convert type ... via a built-in conversion
    return _ExtractFoo((CoreService.Customer) customer);

    // #2 - Safe cast, results in error:
    //      Cannot convert type ... via a built-in conversion
    return _ExtractFoo(customer as CoreService.Customer);

    // #3 - Works for compiler, breaks at runtime where 'casted' is null
    dynamic d = customer;
    var casted = d as CoreService.Customer;
    return _ExtractFoo(casted);
}

一个简单的修复可以正常工作首先序列化为json:

private static string _ExtractFoo(ProductService.Customer customer) {
        // awkward hack - but it blends!
        var serialized = JsonConvert.SerializeObject(customer);
        var deserialized = JsonConvert.DeserializeObject<CoreService.Customer>(serialized);

        return _ExtractFoo(deserialized);
}

考虑到两个对象的属性和值保证匹配,这个工作有意义。虽然这很昂贵,但似乎没必要。

另一种选择是使用implicit conversion operator。但是,考虑到对象是服务生成的,我还没有看到如何使用运算符扩展两个对象。

关键是,这是否是最佳做法。也不知道如何在不同的服务引用之间重用相同的共享对象。我很清楚这个黑客的尴尬。从语言的角度来看,我觉得这是一个有趣的挑战。

这让我想到了一个实际的问题:是否有一种更优雅的方式来欺骗编译器吞下这个,或者更好的说法,在两个之间制作一个更便宜的演员/拳击“不同但是相同的“对象,允许我重用_ExtractFoo()实现?

更新I - 让外部Web服务使用通用接口不是一种选择。此外,最好知道Customer对象具有嵌套属性和子对象的深层次结构;使用像AutoMapper或手动地图这样的东西会很麻烦(更不用说容易出错了)。

更新II - 为了将来参考,我试图解释我的问题/问题是我如何修改_ExtractFoo()方法 - 或其实现 - 所以它可以是适用于CoreService.CustomerProductService.Customer(考虑到上述所有内容)。在“请列出所有其他替代方案”的意义上,它绝对不是一个悬而未决的问题,尽管在我看来提供的答案肯定是可行的选项。

1 个答案:

答案 0 :(得分:1)

在我的头顶,你的选择是:

  1. 获取两个源类以实现相同的接口并传递它而不是具体类型。这将是更好的选择,但我猜这里不可能。
  2. 反序列化并序列化以在类型之间进行转换。您已经拥有此代码,但就像您说它可能会很慢。
  3. 使用AutoMapper等映射库在类型之间进行转换。这非常快,但需要你从Nuget引入一个外部库(我已多次使用AutoMapper)
  4. 自己手动映射属性。这可能是最快的代码,但编写起来非常糟糕。
  5. 在链中一直使用dynamic,而不只是在顶部。您丢失了编译时类型检查,但它应该相当快。例如,而不是像这样的函数:

    public static string _ExtractFoo(ProductService.Customer customer)
    {
        return customer.DoSomethingExciting();
    }
    

    你会有这个:

    public static string _ExtractFoo(dynamic customer)
    {
        return customer.DoSomethingExciting();
    }
    

    如果您需要,可以添加一些检查以确保customerProductService.CustomerCoreService.Customer

相关问题