在 C# 中,我可以将 MyService<Child> 转换为 MyService<Base> 吗?

In C# can I cast MyService<Child> to MyService<Base>?

背景: 我们有一个 ASP.NET 基于 Core 的 Web 应用程序,它使用在 DI 和通用存储库模式之上开发的 EF Core。所以,大部分事情都是使用接口完成的。现在,我们已经到达主 table 维护模块。我们不想为所有 10-20 位主 table 复制相同的服务(由存储库支持)class。

因此,我们创建了一个 _ModelMasterBase class 并从中派生了所有主 table classes。所有 master tables 的 CRUD 都是相同的。所以,接下来我们实现了 MasterRepository<T>MasterService<T> 和它们的接口。现在一切都必须使用 <T>,其中 T 是页面上选择的用于执行 CRUD 的主 table 的类型。

最初,我希望 IMasterService<_ModelMasterBase> 的实例可以转换为 IMasterService<T> - 同样,T 可能是 class _ModelMasterBase 派生的 - 但这似乎不可能!我尝试了运算符、转换和几乎所有我能做的 google!同样由于存储库模式,所有内容都必须是强类型的。

现在,我们已经根据 SO Post -

使用技巧将子 obj 转换为基础 class obj
DerivedClass B = new DerivedClass();
BaseClass bc = JsonConvert.DeserializeObject<BaseClass>(JsonConvert.SerializeObject(B));

我知道这是一个有点肮脏的技巧,但有时它可以方便地保持设计和复杂性之间的权衡。我们谨慎使用它。我希望有类似的东西,以防我想将 MyService<Base> 转换为 MyService<Child>

或者你可以忘记这一切,并指导我为我所有的主人 tables 提供单点 CRUD 服务 - 将同样的事情复制 10-20 次似乎是不合理的。抱歉,我无法深入解释,因为它会拉伸 post.

这是一个 v.basic sample of my code structure,最后您会看到我们正在努力实现的目标。希望对你有帮助。


解决方案:

Based on mkArtak's suggestion, I was able to crack it by using 'Covariance' concept (example). Here's my updated code sample. Now there's a single controller and service layer for all master tables!

继承问题?

这种事情听起来你应该更喜欢组合而不是继承。正如您所说的,您可以 serialize/deserialize 您的专用 class 到您的基础 class,根据定义,这不是更像是一个数据传输对象吗?我不会将逻辑放入其中,而是引入另一个使用基本 class 逻辑而不继承的服务(例如,将实例传递给构造函数)——这可能首先解决问题。

不是解决方案

关于您的特定问题:如果限制不太严格,您也许可以使用 contravariant type parameter(例如,您只能在参数中使用类型参数,而不能在 return 类型中使用)并且您拥有相关接口。但是编译器只允许我以相反的方式分配服务——这是有道理的。也许您会以 协变 方式找到解决方案?

using System;

public class Program
{
    internal interface IMasterService<in T> {
        void DoSomething(T table);
    }

    internal class BaseClass {}

    internal class DerivedClass : BaseClass {}

    internal class SpezializedService : IMasterService<BaseClass> {
        public void DoSomething(BaseClass table) {}
    }

    public static void Main()
    {
        // The compiler isn't happy about the other way around
        IMasterService<DerivedClass> baseService = new SpezializedService();
    }
}

希望对您有所帮助。

简答:在 IMasterService 定义前缀 T 中带有 'out' 关键字。

public interface IMasterService<out T>
{
    // your existing methods' definitions here
}

它叫做Covariance,在MSDN中有描述。