2014-08-27 8 views
9

Ho una classe con un membro Predicate che vorrei utilizzare in un'espressione Linq:Conversione di un predicato <T> ad un Funz <T, bool>

using System.Linq; 

class MyClass 
{ 

    public bool DoAllHaveSomeProperty() 
    { 
     return m_instrumentList.All(m_filterExpression); 
    } 

    private IEnumerable<Instrument> m_instrumentList; 

    private Predicate<Instrument> m_filterExpression; 
} 

Come ho letto che "Predicate<T> è [...] completamente equivalente a Func<T, bool> "(see here), mi aspetto che funzioni, poiché All accetta come argomento: Func<Instrument, bool> predicate.

Tuttavia, ottengo l'errore:

Argument 2: cannot convert from 'System.Predicate<MyNamespace.Instrument>' to 'System.Type' 

C'è un modo per convertire il predicato ad un argomento che questa funzione sarà ingoiare?

risposta

7
public bool DoAllHaveSomeProperty() 
{ 
    return m_instrumentList.All(i => m_filterExpression(i)); 
} 
+0

Aha, funziona, grazie! Quindi Predicato e Func non sono chiaramente ** completamente ** uguali, almeno non semanticamente parlando! – Yellow

+1

Sono semanticamente uguali. Solo non sintatticamente. –

+0

Oops, questo è quello che intendevo. :-) – Yellow

6
return m_instrumentList.All(i => m_filterExpression(i)); 
9

I due tipi rappresentano la stessa firma logica, ma questo non significa che sono solo intercambiabili. Ad esempio, un compito semplice non funzionerà, ma è possibile creare un nuovo Func<T, bool> da Predicate<T, bool>. Esempio di codice:

Predicate<string> pred = x => x.Length > 10; 
// Func<string, bool> func = pred; // Error 
Func<string, bool> func = new Func<string, bool>(pred); // Okay 

Questo è un po 'come avere due tipi enum con gli stessi valori - è possibile convertire tra di loro, ma devi farlo in modo esplicito. Sono ancora tipi separati.

Nel vostro caso, questo significa che si potrebbe scrivere:

public bool DoAllHaveSomeProperty() 
{ 
    return m_instrumentList.All(new Func<T, bool>(m_filterExpression)); 
} 

L'approccio espressione lambda suggerito da altre risposte funzionerà anche, naturalmente.

1

Dal momento che ci sono molte risposte ne aggiungerò un'altra ancora solo per divertimento. Se si desidera che il codice per compilare è possibile utilizzare metodi di extention

//Original Code 
class MyClass4 
{ 
    public bool DoAllHaveSomeProperty() 
    { 
     return m_instrumentList.All(m_filterExpression); 
    } 

    private IEnumerable<Instrument> m_instrumentList; 

    private Predicate<Instrument> m_filterExpression; 
} 

Aggiungere questa classe nello stesso namespace

public static class MyExtentions 
{ 
    public static bool All(this IEnumerable<Instrument> enumer, Predicate<Instrument> pred) 
    { 
     return enumer.All(e => pred(e)); 
    } 
} 
2

È possibile convertire un predicato a un metodo chiamando Invoke. Tutti i delegati hanno questo membro. I delegati non hanno identità strutturale, ma i metodi possono essere convertiti in delegati corrispondenti. Questa correzione ha un costo minore delle prestazioni, in quanto aggiunge un ulteriore livello di riferimento indiretto. Tuttavia, la maggior parte delle soluzioni a questo problema presenta questo problema. Eric Lippert discute questo in modo più dettagliato a http://blog.coverity.com/2014/06/18/delegates-structural-identity.

Nel vostro caso specifico, sostituire return m_instrumentList.All(m_filterExpression); con return m_instrumentList.All(m_filterExpression.Invoke);

codice di esempio che dimostra il problema reale.

void Main() 
{ 
    Predicate<int> t1 = Foo; 
    Func<int,bool> t2 = Foo; 
    Predicate<int> t3 = t2.Invoke; //Legal 
    Func<int,bool> t4 = t1.Invoke; //Legal 
    Predicate<int> t5 = t2; //Illegal 
    Func<int,bool> t6 = t1; //Illegal 
} 

bool Foo(int x) 
{ 
    return x > 20; 
} 
Problemi correlati