繁体   English   中英

C# 8 默认接口实现与继承

[英]C# 8 default interface implementation and inheritance

我想使用 C# 8 默认接口实现来解决我的代码中的性能问题。

实际上,我有这个接口:

public interface IDataAdapter {}
public interface IDataAdapter<T> : IDataAdapter
{
   void Insert(T value);
}

我实际上必须对所有IDataAdapter进行反射,检查泛型类型并通过反射为特定 T 实例调用Insert 我希望做的是:

public interface IDataAdapter 
{
   void InsertValue(object value);
}
public interface IDataAdapter<T> : IDataAdapter
{
   void Insert(T value); 
   public void InsertValue(object value) => Insert(value as T);
}

编译器说要使用关键字 new 来屏蔽继承的方法。 但是,我想要完成的唯一事情是已经实现了一个非泛型方法,以使所有IDataAdapter<T>实现只需要实现泛型版本。

这是我可以完成的事情还是仍然不可能? 我已经知道使用抽象类是解决这个问题的一种方法,但我想让开发人员拥有一个实现许多 IDataAdapter 的类......

这是我当前的反射代码:

public IEnumerable<IDataAdapter> DataAdapters { get; }

    public Repository(IEnumerable<IDataAdapter> dataAdapters)
    {
        DataAdapters = dataAdapters;
    }

    public async Task SaveAsync()
    {
        foreach (var item in aggregates)
        {
            foreach (var dataAdapter in DataAdapters)
            {
                if (dataAdapter.GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericArguments()[0] == item.GetType()))
                {
                    dataAdapter.GetType().GetMethod("Insert", new[] { item.GetType() }).Invoke(dataAdapter, new[] { item });
                }
            }

        }
    }

我认识到这个问题,您需要查找知道如何处理某种类型项目的 IDataAdapter 实现。 我已经为“视图插件”系统做了类似的事情,我会在其中寻找知道如何呈现某种类型的视图插件。 如果您不能提前知道需要渲染什么类型的对象,这将非常有用。

据我所知,试图将更多的编译时类型安全强加到这种模式中是行不通的,否则它实际上不会提供任何好处。 我会像这样声明 IDataAdapter:

public interface IDataAdapter 
{
   void InsertValue(object value);
   Type SupportedType { get; }
}

如果数据适配器支持多种类型,您可以改为使用IEnumerable<Type> SupportedTypes ,或者用bool SupportsType(Type)方法替换该属性。

从面向对象的角度来看,您尝试做的事情无法完成。

假设您创建以下类层次结构:

public interface  IFoo{}
public interface  IBar{}
public class A: IFoo{}
public class B: IFoo{}
public class C:IFoo,IBar {}

然后是以下适配器:

public class TestA : IDataAdapter<A>{}
public class TestB : IDataAdapter<B>{}
public class TestC : IDataAdapter<C>{}
public class TestIFoo : IDataAdapter<IFoo>{}
public class TestIBar : IDataAdapter<IBar>{}
public class TestIBoth : IDataAdapter<IFoo>,IDataAdapter<IBar>{}

如果 TestA 接收到 A 的实例会发生什么很容易。 但是 TestIFoo 收到 C 怎么办? 目前,您的反射代码将无法工作,因为您测试了类型相等性(C 是否等于 IFoo?不!即使 C 作为 IFoo 还可以)。 这打破了 Liskov 替换原则。 如果某些东西适用于一个类,那么它也应该适用于它的任何子类。

假设您解决了上述问题。 现在 TestIBot 收到 C 怎么样? 其中有两种不同的 Insert 实现吗? 当然,这是继承所必需的! 但是……你必须插入 C 两次吗? 或者您是否必须在第一种拟合方法中插入一次?

你必须经过反思的原因是因为所有这些问题都需要一个算法的答案。 您的编译器将无法回答(这使得语言阻止了它)

最后,我强烈建议使用一种非常不同的解决方案(例如 Wim Coenen 提出的解决方案)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM