2010-05-05 85 views
19

有没有办法在C#中编写基于接口的代码(即使用接口而不是类作为接受和传递的类型)而不放弃类似隐式转换的使用?这里有一些示例代码 - 已经删除了很多,但这些是相关的部分。定义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#方式是什么?)

+3

Hasbro在人们使用拼字游戏名称时并不总是发挥出色。 – 2010-05-05 19:24:15

回答

6

您无法在接口上定义强制转换或运算符重载。由于接口是描述总是可用的成员(无论是作为显式转换到该接口还是作为公共成员)的合约,并且只有接口才能包含任何类型的内置逻辑,例如如何投射或运营商将如何使用该界面执行。

您仍然可以从实现接口的抽象基类继承,并提供强制转换或运算符重载所需的逻辑。这并不违反面向接口的设计。不从公共基类继承而是实现接口的类仍然需要独立地实现它们自己的隐式强制转换和运算符重载。如果您希望集中处理通常实现接口的类的逻辑,您可以在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(); 
} 

然后在一个抽象基类,你可以定义一个内隐/显式类型转换,并有ToTargetType()实施只是调用转换运算符例如

public abstract class SomeAbstractClass : ISomeInterface 
{ 
    public TargetType ToTargetType() 
    { 
    return (TargetType)this; 
    } 

    public static explicit operator TargetType(SomeAbstractClass obj) 
    { 
    //Actual cast logic goes here 
    } 
} 

这种方式可以确保实现提供施展必要的类型,这样纯粹的接口驱动的代码可以调用接口的方法来进行转换的一种手段。但是,使用具有演员操作员定义的接口的具体实现的代码可以使用它们代替