tags:

views:

177

answers:

1

Is there a way to write interface-based code (i.e. using interfaces rather than classes as the types accepted and passed around) in C# without giving up the use of things like implicit casts? Here's some sample code - there's been a lot removed, but these are the relevant portions.

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

And in ScrDictionary.cs, we have...

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

And the interface...

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

I want to be able to use IScrDictionary instead of ScrDictionary, but still be able to implicitly convert a ScrDictionary to a Game.VariantInfo. Also, while there may be an easy way to make this work by giving IScrDictionary a property of type Game.VariantInfo my question is more generally: Is there a way to define casts or operator overloading on interfaces? (If not, what is the proper C# way to maintain this functionality without giving up interface-oriented design?)

+1  A: 

You cannot define casts or operator overloading on interfaces. Since an interface is a contract that describes the members which will always be available (either as an explicit cast to that interface or as public members) and nothing more you cannot rely on interfaces to contain any sort of built in logic such as how to cast or how operators will perform with that interface.

You can still inherit from an abstract base class which implements the interface and provides the logic you need for casts or operator overloading. This doesn't violate interface oriented design. Classes which do not inherit from the common base class but implement the interface will still need to independently implement their own implicit casts and operator overloads. If you wish to centralize the logic for working with classes that commonly implement an interface you can do so in C# 3.0+/.NET Fx 3.5 with extension methods (or in previous versions with static methods). Below I demonstrate this with a utility class and two classes, Foo and Bar, which don't have a common ancestor. They share the code which comprises the utility function Add so you don't have to repeat this implementation in both classes.

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

If your interfaces contained more than just contracts that would be violating design by contract.

cfeduke