为C#接口定义隐式和显式转换

时间:2010-05-05 19:19:32

标签: c# interface

有没有办法在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#方式是什么?)

2 个答案:

答案 0 :(得分:7)

您无法在接口上定义强制转换或运算符重载。由于接口是一个描述永远可用的成员的契约(作为对该接口的显式强制转换或作为公共成员),你不能再依赖接口来包含任何类型的内置逻辑,例如如何转换或运营商如何使用该界面执行。

您仍然可以从实现接口的抽象基类继承,并提供转换或运算符重载所需的逻辑。这不违反面向接口的设计。不从公共基类继承但实现接口的类仍然需要独立实现它们自己的隐式转换和运算符重载。如果您希望集中逻辑以使用通常实现接口的类,则可以使用扩展方法(或使用静态方法的先前版本)在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();
    }
}

如果您的界面不仅包含违反合同设计的合同。

答案 1 :(得分:4)

执行此操作的一种方法是,如果存在您经常需要的强制转换或转换,则在您的界面上定义显式方法,例如

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();
  }
}

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