2009-09-23 21 views
16

En C#, puedo implementar una interfaz genérica dos veces en una sola clase, utilizando dos diferentes tipo de parámetros:La implementación de la misma interfaz en diferentes instancias genéricas

interface IFoo<T> { void Foo(T x); } 

class Bar : IFoo<int>, IFoo<float> 
{ 
    public void Foo(int x) { } 
    public void Foo(float y) { } 
} 

me gustaría hacer lo mismo en C#:

type IFoo<'a> = abstract member Foo : 'a -> unit 

type Bar() = 
    interface IFoo<int> with 
     [<OverloadID("int")>] 
     member this.Foo x =() 

    interface IFoo<float> with 
     [<OverloadID("float")>] 
     member this.Foo x =() 

Pero da un error del compilador:

This type implements or inherits the same interface at different generic instantiations 'IFoo<float>' and 'IFoo<int>' . This is not permitted in this version of F#.

no puedo encontrar ninguna discussion of this issue en la web. ¿Se desaprueba ese uso por alguna razón? ¿Hay planes para permitir esto en un próximo lanzamiento de F #?

+0

función planificada para F # 4.0 http://fslang.uservoice.com/forums/245727- f-language/suggestions/5663504-allow-to-implement-the-same-interface-at-different – foobarcode

+0

La solicitud de extracción se puede encontrar en: https://github.com/Microsoft/visualfsharp/pull/18 – forki23

Respuesta

11

En este momento no sé de planes para permitir esto. . La característica has been planned y está, al menos parcialmente (ver comentarios) implementada en F # 4.0.

Creo que las únicas razones por las que actualmente no se permiten son que no es trivial de implementar (especialmente con inferencia de tipo F #) y rara vez se presenta en la práctica (solo recuerdo que un cliente preguntó sobre esto).

Dada una cantidad infinita de tiempo y recursos, creo que esto estaría permitido (puedo imaginar que esto se añada a una versión futura del lenguaje), pero en este momento no parece que esta sea una característica que valga la pena el esfuerzo de apoyo. (. Si conoces un caso de fuerte motivación, por favor enviar por correo [email protected]rosoft.com)

EDITAR

Como un experimento para los curiosos, he escrito este C#:

public interface IG<T> 
{ 
    void F(T x); 
} 
public class CIG : IG<int>, IG<string> 
{ 
    public void F(int x) { Console.WriteLine("int"); } 
    public void F(string x) { Console.WriteLine("str"); } 
} 

y se hace referencia desde F # (con comentarios que sugieren los resultados)

let cig = new CIG() 
let idunno = cig :> IG<_> // type IG<int>, guess just picks 'first' interface? 
let ii = cig :> IG<int> // works 
ii.F(42)     // prints "int" 
let is = cig :> IG<string> // works 
is.F("foo")    // prints "str" 

así que esto es lo que suele ocurrir en estas cosas 'frontera' con F # - F # puede consumir estas cosas bien, incluso si no puede ser autor del sa me cosas desde dentro del lenguaje.

+2

Er, entonces ¿Cómo se trataría la inferencia tipo F # con tales tipos escritos en C#, entonces? En cuanto a la lógica, bueno ... las especificaciones de ECMA CLI definen varias categorías de cumplimiento de CLS; uno de ellos es "extensor CLS". Un requisito para eso es: "Capaz de ... Implementar cualquier interfaz compatible con CLS". –

+0

Para ampliar el comentario de Pavel, ¿qué sucede si define una interfaz no genérica 'I' en C# que extiende tanto' IG 'como' IG '? ¿Se puede implementar esta interfaz desde F #? – kvb

+0

@kvb, no, esa interfaz no se puede implementar desde F #. – Brian

0

Hay una forma razonable aunque no elegante de hacerlo, crear un nuevo tipo para cada interfaz aquí es un ejemplo de consumir múltiples eventos de un ESB (nSvcBus) que requiere que cada evento corresponda a una interfaz implementada. El primer tipo siguiente contiene el código genérico de 'manipulador', los otros tipos simplemente implementan la interfaz y llamar al controlador genérico

type public nSvcBusEvents() = 

    member this.HandleEvents(msg:IEvent) =() 
     //handle messages ie: let json = JsonConvert.SerializeObject(msg) 

type public ActionLoggedHandler() = 
    interface IHandleMessages<Events.ActionLoggedEvent> with 
     member this.Handle(msg : ActionLoggedEvent) = 
      nSvcBusEvents().HandleEvents(msg) 

type public ActionCompletedHandler() = 
    interface IHandleMessages<Events.ActionCompletedHandler> with 
     member this.Handle(msg : ActionCompletedHandler) = 
      nSvcBusEvents().HandleEvents(msg) 

type public ActionFailedHandler() =  
    interface IHandleMessages<Events.ActionFailedHandler> with 
     member this.Handle(msg : ActionFailedHandler) = 
      nSvcBusEvents().HandleEvents(msg) 
Cuestiones relacionadas