2009-02-12 8 views
7

Estoy tratando de encontrar una manera para emitir automáticamente algo que una acción o Func y lo mejor que se puede llegar a decir algo como esto:¿Por qué no puedo convertir implícitamente un delegado con métodos de extensión?

[TestFixture] 
public class ExecutionTest 
{ 
    public void BadMethod() 
    { 
     throw new Exception("Something bad happened"); 
    } 

    [Test] 
    public void TestBadMethod() 
    { 
     // Want this, but it won't work!! 
     // BadMethod.Execute().IgnoreExceptions(); 

     // Ick 
     ((Action)BadMethod).Exec().IgnoreExceptions(); 

     // Still ick 
     ((Action)BadMethod).IgnoreExceptions(); 

     // Do not want 
     ExtensionMethods.Exec(BadMethod).IgnoreExceptions(); 

     // Better but still meh 
     this.Exec(BadMethod).IgnoreExceptions(); 

    } 
} 

public static class ExtensionMethods 
{ 
    public static Action Exec(this Action action) 
    { return action; } 

    public static Action Exec(this object obj, Action action) 
    { return action; } 

    public static void IgnoreExceptions(this Action action) 
    { 
     try { action(); } 
     catch {} 
    } 
} 

Tiene que una manera mejor/más fácil de hacer esto, algún pensamiento?

Respuesta

5

En C#, cuando utiliza el nombre del método sin paréntesis, se denomina grupo de métodos y no tiene otra representación que no sea en tiempo de compilación. Un grupo de métodos puede representar más de un método (debido a sobrecargas y anulaciones), por lo tanto, para identificar implícitamente qué método es necesario, debe proporcionarse un tipo de delegado objetivo.

En su caso, se estará preguntando por qué el tipo de parámetro del método de extensión no desencadenará la resolución de la función. En pocas palabras, la extensión se evalúa después de que se conoce el tipo, es decir, este parámetro no se puede usar como un objetivo de conversión implícito.

ejemplo de por qué se rompería:

class Test 
{ 
    void M (void) // Fits Action delegate 
    { 
    } 

    int M (int) // Fits Func<int,int> delegate 
    { 
     return 5; 
    } 

    void Test() 
    { 
     M.Exec(); // UHOH!!! Which Exec to resolve to ??? 
    } 
} 


public static class Extensions 
{ 
    public static void Exec(this Action action) { } 
    public static void Exec(this Func<int, int> func) { } 
} 

Como se puede ver, hay un conflicto, sino como una cuestión de hecho, el conflicto nunca sucede porque C# ni siquiera tratar de encontrar una coincidencia extensión con un grupo de métodos.

Nota cómo esto no va a funcionar bien:

class A 
{ 
    public static implicit operator int (A a) 
    { 
     return 5; 
    } 

    void F() 
    { 
     A a = new A(); 
     a.Blah(); // Error! It won't implicitly try C.Blah() 
    } 
} 

public static class C 
{ 
    public static void Blah (int i) 
    { 
    } 
} 

C# no coincidirá A-C.Blah(int) porque requeriría una conversión implícita.

+0

No estoy seguro de que sea un problema de sobrecarga de métodos porque el compilador decidirá a cuál llamar. Pero esta es la mejor respuesta que he visto hasta ahora ... –

2

Como Coincoin dice, no va a funcionar bien en C# debido al amor excesivo por la sobrecarga de métodos. La única solución que he visto usar a la gente es la creación de acción y métodos: Func

public Action Action(Action f) { return f; } 
public Action<A> Action<A>(Action<A> f) { return f; } 
... 
public Func<A,B,C,D,E> Func(Func<A,B,C,D,E> f) { return f; } 

Incluso se puede llamar a todos "F" para obtener algún tipo de sintaxis corta:

F(BadMethod).NoExceptions(); 

Usted podría decide no definir estos métodos en tu clase, y ponerlos en una utilidad de Funcs o algo así. Alias ​​de TI con F y que no termine tan mal:

F.F(BadMethod).NoException(); 

Pero en general, aún se chupa :(

+0

Sí, es por eso que tuve el método de extensión para (este Objeto Object, Acción) para que funcione dentro de cualquier clase llamando a this.Action() o this.Func() –

+0

Lo siento, no vi t Definición de Exec: nombre algo engañoso, no: P – MichaelGG

+0

Sí, lo renombré en mi código actual. Parecía "fluido" en ese momento. –

1

F # le permite hacer este tipo de cosa muy natural, proporcionando un tipo mucho mejor inferencia. sistema.

Cuestiones relacionadas