2010-05-05 13 views
19

C'è un modo per scrivere codice basato sull'interfaccia (ad esempio utilizzando interfacce anziché classi come i tipi accettati e passati) in C# senza rinunciare all'uso di cose come i cast impliciti? Ecco alcuni esempi di codice: ce ne sono stati molti rimossi, ma queste sono le parti rilevanti.Definizione dei cast impliciti ed espliciti per le interfacce C#

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

E in ScrDictionary.cs, abbiamo ...

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

E l'interfaccia ...

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

Voglio essere in grado di utilizzare al posto di IScrDictionaryScrDictionary, ma essere ancora in grado di convertire implicitamente uno ScrDictionary in un Game.VariantInfo. Inoltre, mentre potrebbe esserci un modo semplice per farlo funzionare dando a IScrDictionary una proprietà di tipo Game.VariantInfo la mia domanda è più in generale: C'è un modo per definire i cast o l'overloading degli operatori sulle interfacce? (In caso contrario, qual è il modo C# corretto per mantenere questa funzionalità senza rinunciare alla progettazione orientata all'interfaccia?)

+3

Hasbro non ha sempre suonato bene quando le persone usano il nome Scrabble ... –

risposta

6

Non è possibile definire il cast o l'overloading dell'operatore sulle interfacce. Dato che un'interfaccia è un contratto che descrive i membri che saranno sempre disponibili (sia come cast esplicito a quell'interfaccia o come membri pubblici) e nient'altro non si può fare affidamento sulle interfacce per contenere alcun tipo di logica incorporata come il cast o come gli operatori si esibiranno con quell'interfaccia.

È ancora possibile ereditare da una classe base astratta che implementa l'interfaccia e fornisce la logica necessaria per i cast o per l'overloading dell'operatore. Ciò non viola la progettazione orientata all'interfaccia. Le classi che non ereditano dalla classe base comune ma implementano l'interfaccia dovranno comunque implementare autonomamente i propri cast impliciti e sovraccarichi dell'operatore. Se si desidera centralizzare la logica per lavorare con classi che comunemente implementano un'interfaccia, è possibile farlo in C# 3.0 + /. NET Fx 3.5 con metodi di estensione (o nelle versioni precedenti con metodi statici). Di seguito lo dimostrerò con una classe di utilità e due classi, Foo e Bar, che non hanno un antenato comune. Condividono il codice che comprende la funzione di utilità Aggiungi in modo da non dover ripetere questa implementazione in entrambe le classi.

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

Se le vostre interfacce contenevano più di semplici contratti che avrebbero violato la progettazione per contratto.

2

Un modo per farlo è se c'è un cast/conversione che è probabile che dovrai spesso definire è come un metodo sul tuo inteface, ad es.

public interface ISomeInterface 
{ 
    TargetType ToTargetType(); 
} 

Poi, in una classe base astratta è possibile definire un implict/cast esplicito e hanno l'attuazione di ToTargetType() basta chiamare l'operatore di cast per esempio

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

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

questo modo si garantisce che le implementazioni forniscono un mezzo per lanciare al tipo necessaria affinché puramente interfacciare codice guidato può chiamare il metodo di interfaccia per eseguire la conversione. Ma il tuo codice che usa le implementazioni concrete di quell'interfaccia che hanno gli operatori di cast definiti può usarli invece

Problemi correlati