【问题标题】:Implicit conversion between equivalent interfaces等效接口之间的隐式转换
【发布时间】:2017-05-10 23:10:10
【问题描述】:

假设我有以下界面:

public interface IMap<S, T>()
{
  T Map(S source);
}

根据我使用的泛型类型参数,使用它的实现可能会变得很麻烦(即IMap&lt;int, IEnumerable&lt;SomeOtherType&gt;&gt;

为了在本地简化事情,我希望能够声明一个显式命名的接口版本,例如:

public interface IMyMap : IMap<int, IEnumerable<SomeOtherType>> {}

不需要额外的方法;只是为了减少使用它的麻烦(特别是如果它归结为通过反射进行实例化)。

但是,如果我可以将具有完全相同类型参数的 IMap 的任何实现转换为特定命名的类型,我也更愿意。这不是 C++ Typedef,它非常适合我正在寻找的东西,这是 C#。

我可以编写一个接受任何形式的IMap&lt;int, IEnumerable&lt;SomeOtherType&gt;&gt; 并包装调用的实现。不过,这似乎最终会带来更多的麻烦而不是实现它的价值。

编辑:例如,我希望按照以下方式做一些事情:

public class SomeOtherType { }
public interface IMap<S, T> { T Map(S source); }
public interface IMyMap : IMap<int, IEnumerable<SomeOtherType>> {}

public class Main
{
  public Main(IMap<int, IEnumerabel<SomeOtherType>> input)
  {
    IMyMap wrapped = input;
  }
}

显然,这种请求严重依赖于IMyMap 没有比它实现的接口更多的定义。

tehDorf 提供的解决方案在我想要的范围内;但是,我也在寻找其他可能的解决方案,例如通过包装器工作:

public class MyMapWrapper : IMyMap
{
  private IMap<int, IEnumerable<SomeOtherType>> wrapped;
  public MyMapWrapper(IMap<int, IEnumerable<SomeOtherType>> wrapped)
  { this.wrapped = wrapped; }

  public IEnumerable<SomeOtherType> Map(int source) { return wrapped.Map(source); }
}

还有其他不同的方法来做我正在寻找的事情吗?尤其是任何不属于单个文件的内容。

【问题讨论】:

  • 我想我已经明白了。而且我认为您发布的代码正是您想要做的。您正在实现适配器模式。你有一个实现一个接口的类,你需要它来实现一个不同的接口。你所说的“包装器”是一个适配器。没有隐含的方法。
  • 我感到困惑的原因是因为tehDorf建议和使用包装器是完全不相关的解决方案并且解决完全不同的问题。我不认为他们俩都可以解决同一个问题。
  • @ScottHannen 抱歉,我并不完全熟悉所有不同的模式名称。我看到它的方式是,在这个特定的实例中,我可以使用 using 别名将 IMyMap 定义为 IMap<...> 在使用并使用 IMyMap 实例的类的同一文件中 - 但是,别名仅存在于该文件中。或者,我可以将 IMyMap 定义为接口(项目范围的定义而不是本地文件),在上述类中使用它,并使用适配器模式来包装碰巧使用完全相同类型参数的 IMap 的任何非 IMyMap 实现.

标签: c# generics interface casting


【解决方案1】:

您可以添加using alias directive(谢谢itsme86):

using IMyMap = IMap<int, IEnumerable<SomeOtherType>>;

然后,在代码中你可以使用IMyMap,像这样:

using System.Collections.Generic;
using IMyMap = SomeExample.IMap<int, System.Collections.Generic.IEnumerable<bool>>;

namespace SomeExample
{
    public interface IMap<T, S>
    {
        T Map(S source);
    }

    public class ExampleUsage
    {
        public IMyMap Foo { get; set; }

        public void SetFoo()
        {
            Foo = (IMyMap) new object();
            Foo = (IMap<int, IEnumerable<bool>>) new object(); // Same thing
        }
    }
}

不过,您必须将 using alias 指令添加到您想在其中使用它的任何代码文件中。

【讨论】:

  • 它被称为using alias
  • 这不符合 OP 的要求。它不会将IMap&lt;S, T&gt; 转换为IMyMap
  • @Rob OP 想要使用IMap&lt;int, IEnumerable&lt;SomethingElse&gt;&gt; 做一些事情来减少麻烦。他们特别声明“这不是 C++ Typedef,非常适合我正在寻找的东西,这是 C#。” - 我将其解释为“OP 不知道现在 C# 中有类似的功能”。想要制作另一个接口的例子是 OP 对 C# 中可能发生的事情的最佳猜测。
  • @Rob 对于我的问题不够清晰,我深表歉意 - 这是我正在寻找的解决方案的领域。我将修改部分问题。
  • @tehDorf 够公平的。如果您想稍微编辑您的答案(也许删除划掉的文本),我将能够删除我的反对票;因为它目前已锁定。
【解决方案2】:

你可以这样做:

public interface IMap<S, T>
{
    T Map(S source);
}

public class SomeClass { }
public class ThatClass { }

public interface IMapOfSomething : IMap<SomeClass, ThatClass> { }

public class Map : IMapOfSomething
{
    ThatClass IMap<SomeClass, ThatClass>.Map(SomeClass source)
    {
        throw new NotImplementedException();
    }
}

您可以将Map 转换为IMapIMap&lt;SomeClass, ThatClass&gt;
您可以将IMap 转换为IMap&lt;SomeClass, ThatClass&gt;

这部分不清楚:

如果我可以将具有完全相同类型参数的任何 IMap 实现转换为该特定命名的类型,我也更愿意。

如果该类没有实现IMap——它恰好具有相同的属性和方法——那么不,你不能将它转换为IMap。那将不利于语言。目的是您将故意实现一个接口。如果是故意的,那么您可以通过声明该类实现该接口来表明这一点。

想象一下,如果您可以将某些内容强制转换为IMap 而不实际实现接口,仅仅因为它具有相同的属性和方法,您可能会遇到的麻烦。您可以更改该类,使其不再“看起来像”IMap,但您不会收到任何编译器错误。代码会在运行时失败。

【讨论】:

  • 我将修改我的问题,希望能减轻困惑。
猜你喜欢
  • 2021-06-08
  • 2023-03-10
  • 2012-10-24
  • 2016-06-21
  • 2015-10-20
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
相关资源
最近更新 更多