【问题标题】:Defining implicit and explicit casts for C# interfaces为 C# 接口定义隐式和显式转换
【发布时间】:2010-05-05 19:19:32
【问题描述】:

有没有办法在 C# 中编写基于接口的代码(即使用接口而不是类作为接受和传递的类型)而不放弃使用隐式转换之类的东西?这是一些示例代码 - 已删除很多,但这些是相关部分。

 public class Game
 {
     public class VariantInfo
     {
         public string Language { get; set; }
         public string Variant { get; set; }
     }
 }

在 ScrDictionary.cs 中,我们有...

 public class ScrDictionary: IScrDictionary
 {
     public string Language { get; set; }
     public string Variant { get; set; }

     public static implicit operator Game.VariantInfo(ScrDictionary s)
     {
        return new Game.VariantInfo{Language=sd.Language, Variant=sd.Variant};
     }
 }

还有界面……

 public interface IScrDictionary
 {
     string Language { get; set; }
     string Variant { get; set; }
 }

我希望能够使用IScrDictionary 而不是ScrDictionary,但仍然能够将ScrDictionary 隐式转换为Game.VariantInfo。此外,虽然通过给IScrDictionary 提供Game.VariantInfo 类型的属性可能有一种简单的方法来完成这项工作,但我的问题更普遍:有没有办法在接口上定义强制转换或运算符重载? (如果不是,在不放弃面向接口设计的情况下,保持此功能的正确 C# 方法是什么?)

【问题讨论】:

  • 当人们使用 Scrabble 这个名字时,孩之宝并不总是表现得很好......

标签: c# interface


【解决方案1】:

您不能在接口上定义强制转换或运算符重载。由于接口是描述始终可用的成员的合同(作为对该接口的显式转换或作为公共成员),仅此而已,您不能依赖接口来包含任何类型的内置逻辑,例如如何转换或操作员将如何使用该界面。

您仍然可以从实现接口并提供强制转换或运算符重载所需的逻辑的抽象基类继承。这并不违反面向接口的设计。不从公共基类继承但实现接口的类仍然需要独立实现自己的隐式强制转换和运算符重载。如果您希望集中处理通常实现接口的类的逻辑,您可以在 C# 3.0+/.NET Fx 3.5 中使用扩展方法(或在以前的版本中使用静态方法)这样做。下面我用一个实用程序类和两个没有共同祖先的类 Foo 和 Bar 来演示这一点。它们共享包含实用函数 Add 的代码,因此您不必在两个类中重复此实现。

public interface IInterface
{
    int X { get; set; }
    int Y { get; set; }
}

public static class IInterfaceTHelper
{
    public static IInterface Add<T>(this IInterface a, IInterface b) 
        where T : new()
    {
        var ret = (IInterface)new T();
        ret.X = a.X + b.X;
        ret.Y = a.Y + b.Y;
        return ret;
    }
}

class Foo : IInterface
{
    public int X { get; set; }
    public int Y { get; set; }

    public static IInterface operator +(Foo a, IInterface b)
    {
        return a.Add<Foo>(b);
    }
}

class Bar : IInterface
{
    public int X { get; set; }
    public int Y { get; set; }

    public static IInterface operator +(Bar a, IInterface b)
    {
        return a.Add<Bar>(b);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo { X = 5, Y = 3 };
        var bar = new Bar { X = 3, Y = 5 };

        var result = foo + bar;
        Console.WriteLine(result.GetType().Name + " " + result.X + " " + result.Y);
        result = bar + foo;
        Console.WriteLine(result.GetType().Name + " " + result.X + " " + result.Y);

        Console.ReadLine();
    }
}

如果您的接口包含的不仅仅是合同,那将违反合同设计。

【讨论】:

    【解决方案2】:

    这样做的一种方法是,如果您经常需要进行强制转换/转换,则在您的界面上定义一个显式方法,例如

    public interface ISomeInterface
    {
       TargetType ToTargetType();
    }
    

    然后在抽象基类中,您可以定义隐式/显式转换,并让转换运算符只调用您定义实际转换逻辑的接口方法,例如

    public abstract class SomeAbstractClass : ISomeInterface
    {
      public TargetType ToTargetType()
      {
        // Actual cast logic goes here
        return (TargetType)this;
      }
    
      public static explicit operator TargetType(SomeAbstractClass obj)
      {
        return ToTargetType();
      }
    }
    

    这样可以确保实现提供了一种转换为必要类型的方法。因此纯接口驱动的代码可以调用接口方法进行转换。但是您使用接口的具体实现的代码将定义强制转换运算符,并且可以使用它们来代替

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-21
      • 2012-12-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      • 2023-03-10
      • 2014-11-15
      • 2013-11-17
      相关资源
      最近更新 更多