2013-05-06 13 views
6

Potrebbe essere una domanda stupida, ma per favore aiutatemi a rispondere. Attualmente ho un'interfaccia con 2 metodi generici:Forzare l'utente ad utilizzare il giusto metodo generico in C#

ValidationResult Validate<T>(T t); 


IList<ValidationResult> ValidateList<T>(IEnumerable<T> entities); 

Quello che voglio è che se si desidera convalidare un oggetto, utilizzare il metodo Validate; se si desidera convalidare una matrice di oggetti, utilizzare il metodo ValidateList, abbastanza chiaro in mente e interfaccia. Ma sembra che l'utente possa anche usare il metodo Validate per un elenco di oggetti senza errori del compilatore (ovviamente!). C'è qualche modo per restringerli al metodo ValidateList? Grazie mille.

+2

aggiungi alla vostra dichiarazione di interfaccia – x4rf41

+2

@TimSchmelter Vero, ma è possibile passare un elenco a 'Validate', che è ciò che non vuole – Servy

+1

Convalidare con un oggetto è un sottoinsieme della funzionalità fornita dal metodo ValidateList . Perché non avere un solo metodo specificato nell'interfaccia IList Validate (Entità IEnumerable ); dove possono passare in un oggetto IEnumerable di un oggetto, se questo è tutto ciò che devono essere convalidati. c'è un forte motivo per rompere il caso speciale di un oggetto? –

risposta

2

È possibile limitare una funzione di tipi di oggetti specifici (ei suoi derivati) facendo qualcosa di simile nella dichiarazione di funzione:

ValidationResult Validate<T>(T t) where T : ValidateBase, ValidateBaseOther 

edit:

quindi in questo caso, la funzione solo la volontà prendere oggetti che sono ValidateBase o suoi derivati, o ValidateBaseOther o suoi derivati. Ovviamente si può solo utilizzare uno se si vuole

ValidationResult Validate<T>(T t) where T : ValidateBase 
+0

Si noti che possono ancora sottoporre a hardcast l'oggetto per richiamare l'altra firma. – Aphelion

+3

@Aphelion Non sono sicuro di cosa intendi. Se l'oggetto non è del tipo, il cast fallirebbe giusto? –

+0

puoi trasmettere al basetype con '(ValidateBase)' e quindi inserire la variante non-altra – Aphelion

-1

In breve, non è possibile risolvere il problema (impedire che IEnumerable<> da essere passato a un metodo generico) con i generici. Questo perché non è possibile avere vincoli generici negativi (ad esempio, tutto tranne someClass). L'unica ragione per cui esistono limitazioni generiche è consentire al compilatore di sapere quale firma aspettarsi sul tipo generico. Non è quello di fornire allo sviluppatore segnali di progettazione.

Oltre a requisiti esterni non specificati, è possibile definire il tipo generico all'interfaccia, anziché il metodo. Ciò non garantisce che T non possa implementare IEnumerable<>; tuttavia, fa assicurarsi che ValidateList debba accettare un elenco di ciò che viene passato a Validate. Ciò significa che T può essere una matrice, ma che imporrebbe ValidateList di accettare una matrice di matrici.

Se si lasciano i tipi generici a livello di metodo, anche se entrambi hanno un tipo generico denominato T, questi tipi in realtà non hanno nulla a che fare l'uno con l'altro.

Tipo generico definito all'interfaccia.

public interface ISomeInterface<T> 
{ 
    ValidationResult Validate(T t); 
    IList<ValidationResult> ValidateList(IEnumerable<T> entities); 
} 

questo sarebbe attuata come:

public class SomeClass<T> : ISomeInterface<T> 
{ 
    ValidationResult Validate(T t) 
    { 
     // Do something ... 
    } 
    IList<ValidationResult> ValidateList(IEnumerable<T> entities) 
    { 
     // Do something ... 
    } 
} 

e utilizzato in questo modo:

var myInstance = new SomeClass<int>(); 

int obj = 5; 
int arr = new [] {1,2,3}; 

myInstance.Validate(obj); 
myInstance.ValidateList(arr); 

myInstance.Validate(arr); // should throw compiler error 
+0

L'unico motivo per cui questo sta creando il risultato desiderato è perché stai rimuovendo inferenza di tipo e specificando un tipo generico, che è ciò che risulta nell'errore del compilatore. Se il tipo generico specificato era 'IEnumerable ', il metodo "errato" si compilerebbe e gli altri due fallirebbero. Quindi questo non ti impedisce di usare un elenco nel metodo 'Validate'. – Servy

+0

Tecnicamente, ciò va bene perché allora 'ValidateList' richiederebbe un' IEnumerable > 'che è un array frastagliato rispetto a un array. –

+0

Grazie per la risposta, ma poiché non desidero aggiungere alla dichiarazione dell'interfaccia perché limita la mia classe concreta a una specifica. Pensa se abbiamo 20 oggetti, quindi dobbiamo fare 20 classi concrete di quell'interfaccia ... Lo scopo di questa interfaccia è di convalidare vari tipi di oggetti. Comunque grazie. – TuanHuynh

-1

Dal opzione migliore è stata trovata: Verificare se il tipo di passato a Validate implementa IEnumerable<>. Se è così, forse sollevare un'eccezione ....

Quindi, qui va:

ValidationResult Validate(T t) 
{ 
    Type OutResultNotUsed; 
    if (typeof(T).IsOrInherits(typeof(IEnumerable<>), out OutResultNotUsed)) 
     throw new Exeption("glkjglkjsdg"); 
} 

Metodo di estensione per controllare se un certo tipo è o eredita una definizione generica.

public static bool IsOrInheritsGenericDefinition(this Type ThisType, Type GenericDefinition, out Type DefinitionWithTypedParameters) 
    { 
     DefinitionWithTypedParameters = ThisType; 

     while (DefinitionWithTypedParameters != null) 
     { 
      if (DefinitionWithTypedParameters.IsGenericType) 
      { 
       if (DefinitionWithTypedParameters.GetGenericTypeDefinition() == GenericDefinition) 
        return true; 
      } 

      DefinitionWithTypedParameters = DefinitionWithTypedParameters.BaseType; 
     } 

     return false; 
    } 
+0

La domanda richiede in particolare la convalida del tempo di compilazione. – Servy

+0

Ok, rispondi "Non è possibile", sarà di grande aiuto. –

+0

Questo è un duplicato di un'altra domanda che afferma specificatamente che non è possibile. Ho già votato per chiudere la domanda come duplicato di quell'altro, quindi non c'è bisogno di rispondere. – Servy

-1

Si potrebbe fare la seguente:

public class MultipleValidationResults : ValidationResult, IList<ValidationResult> 
{ 
    // stuff... 
} 

public ValidationResult Validate<T>(T t) 
{ 
    if (t is IEnumerable) 
     // use reflection to call return ValidateList<Y>(t) 
     // (T is IEnumerable<Y>) 
    // other stuff 
} 

MultipleValidationResults ValidateList<T>(IEnumerable<T> entities); 
Problemi correlati