【问题标题】:How to apply functions from one interface to another interface while using generics on a base class?如何在基类上使用泛型时将函数从一个接口应用到另一个接口?
【发布时间】:2019-01-10 08:54:27
【问题描述】:

我有两个来自第三方的具有相同功能的接口。由于这是第三方接口,我无法附加父接口。

public interface IInterface1 {
     int Open(string stringName);
}

public interface IInterface2 {
     int Open(string stringName);
}

我想将它们传递给基类

public class MyClass : BassClass<IInterfaceWithOpenFunction>

这样我就可以以相同的方式在两个类上执行相同的功能。

public class BassClass<T> Where T : IInterfaceWithOpenFunction, new() 
{
    private T item;
    public BaseClass(string stringName) 
    {
        item = new T();
        item.open(stringName);

我不想让项目动态化,因为我想保持智能感知,我该如何实现?

不知何故,IInterfaceWithOpenFunction 需要消耗其他接口的函数 open,同时允许我传入所需的接口来实现。

【问题讨论】:

  • 就语言而言,这些方法并不是“完全相同的功能”,正是因为它们位于不同的接口中。 C# 没有鸭子类型(除非您已经丢弃了动态)。某种类型的检查/转换/适配器将是不可避免的。有很多方法可以给猫换皮,例如,使用 Func&lt;string, int&gt; 委托和一些扩展方法。
  • 当我不得不处理这种类型的问题时,我通常最终会编写具有通用接口的包装类。
  • @juharr,我不拥有这些接口,那么如何将通用接口附加到它们?我希望在运行时不要这样做。
  • @JeroenMostert C# does not have duck typing (barring dynamics)foreach, example here
  • @Flater:技术上正确确实是最好的正确。我将把我的评论修改为“它没有用户可控的鸭子打字”。

标签: c# generics inheritance interface base-class


【解决方案1】:

您可以做的是创建您自己的“父”接口和派生类,每个类都适用于这些不同的第三方类。本质上,对于不同的非相关接口,您有不同的包装器:

public interface IInterfaces
{
    int Open(string stringName);
}

public class DerivedForInterface1 : IInterfaces
{
    private IInterface1 _instance;
    public DerivedForInterface1(IInterface1 instance)
    {
        _instance = instance;
    }

    public int Open(string stringName) => _instance.Open(stringName);
}

public class DerivedForInterface2 : IInterfaces
{
    private IInterface2 _instance;
    public DerivedForInterface2(IInterface2 instance)
    {
        _instance = instance;
    }

    public int Open(string stringName) => _instance.Open(stringName);
}

然后是你的基类:

public class BassClass<T> Where T : IInterface

在上述实现中,第三方接口的特定实例作为包装器的依赖项提供。通过这样做,IInterfaces 上的任何实现都没有默认构造函数,因此您需要删除 new() 通用约束。还有其他实现它的方法,例如通过属性而不是构造函数传递依赖项。不同的方式各有优劣,大家可以看看差异。


至于你的这部分代码:

item = new T();
item.open(stringName);

我认为也许不是像你正在做的那样初始化类型,而是让你的类持有对初始化类型的引用。可能是我展示的包装类可以替换您当前拥有的BaseClass

【讨论】:

  • @CamiloTerevinto - 你是对的并且更正了 - 从问题中获取代码而没有注意..
  • 你会如何处理变量获取?放?是否启用了公共 bool {{get return _instance.enabled} set {_instance.enabled = value;}}
  • @Demodave - 这取决于你想要做什么。还有它有多大的问题。基本上,您正在创建包装器来包装那些第三方接口。如果暴露单个函数或 15..,解决方案会有所不同
  • 我结束了这个解决方案,因为它最适合我的需要,谢谢
【解决方案2】:

如果您坚持使用智能感知和单个经理来统治所有这些,那么可以这样做:

public class Provider1Wrapper : IInterfaceWithOpenFunction
{
    private Provider1 _provider; // Instance\Inject via CTOR

    public int Open(string stringName)
    {
        return _provider.Open(stringName);
    }
}

public class Provider2Wrapper : IInterfaceWithOpenFunction
{
    private Provider2 _provider; // Instance\Inject via CTOR

    public int Open(string stringName)
    {
        return _provider.Open(stringName);
    }
}

public static class ProviderManager<T> where T : IInterfaceWithOpenFunction, new()
{
    public static int Open(string stringName)
    {
        T providerWrapper = new T();
        return providerWrapper.Open(stringName);
    }
}


void Main()
{
    var result = ProviderManager<Provider2Wrapper>.Open(stringName);
}

【讨论】:

    猜你喜欢
    • 2019-04-06
    • 2018-07-23
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 2020-12-05
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多