Proteggere il non iniziato (sviluppatore) dai generici

4

È accettabile avere un parametro generico fittizio nell'elenco dei parametri al fine di salvare gli utenti del metodo dalla necessità di specificare argomenti tipo? Ad esempio:

public T Generate<T>(int paramForInstance) where T : MyClass {
    return MyClass.SomeFactoryMethod<T>(paramForInstance);
}

//calling code needs to specify type
MyDerivedClass instance = Generate<MyDerivedClass>(5);

public T Generate<T>(int paramForInstance, T dummy) where T : MyClass {
    return MyClass.SomeFactoryMethod<T>(paramForInstance);
}

//calling code needs to provide a "sample" to enable type inference
MyDerivedClass instance = null;
instance = Generate(5,instance);

Il presupposto è che se junior altri sviluppatori del team non hanno bisogno di pensare ai generici, hanno meno probabilità di calciare.

A Little Background (sentiti libero di saltare questo passaggio)

Un paio di settimane fa, un tipo di amministratore di gestione del mio team ha dato di matto quando ha visto il codice (il mio codice) che assomigliava a questo:

//conversion methods, using generics
private static TResult? IfNotDangerous<TResult>
  (SomeType firstThing, string name, Func<object, TResult?> conversion) 
  where TResult : struct
{
    return IfNotDangerous(firstThing, name, 
          (any, dummy) => conversion(any), (TResult?)null);
}

private static TResult IfNotDangerous<TResult>
  (SomeType firstThing, string name, Func<object, TResult, TResult> conversion,
  TResult defaultValue)
{
    if (firstThing == null) return defaultValue;
    if (!firstThing.Contains(name)) return defaultValue;
    if (firstThing[name] == DangerousValue) return defaultValue;
    return conversion(firstThing[name], defaultValue);
}

La lamentela che ha avuto è stata: "Perché stai usando una struttura ?! È così pesante in termini di risorse! E cosa significa" dove "significa? Nessuno sullo sviluppo senior sa cosa fa - Ho chiesto a tutti! "

Dopo aver superato la mia autocommiserazione, ho trovato un modo per aggirare che non usava i generici per questo particolare metodo. La pacificazione è stata raggiunta. Ma vorrei evitare problemi in futuro, se possibile.

Modifica

Apprezzo tutto l'incoraggiamento, ma la domanda non era "dovrei cercare altrove il lavoro?" - Era "una soluzione alternativa utilizzabile?"

    
posta sq33G 18.12.2011 - 09:18
fonte

7 risposte

30

Triste vedere i programmatori che non si spostano con i tempi.

Il fatto è che i generici hanno fatto parte di C # e .NET dalla versione 2 e LINQ dalla versione 3. Queste non sono più nuove tecniche all'avanguardia.

Invece di "proteggerli", dovresti insegnarli . Inizia un tutorial settimanale (a pranzo se non hai un buy-in) per tutti gli sviluppatori che sono interessati a rimanere aggiornati.

Il fatto è che se portano un nuovo senior, è probabile che utilizzeranno anche generici e LINQ. Mantenere questi "nascosti" o non usarli è un disservizio agli altri sviluppatori e alla società.

Se ti viene detto di non usare affatto generici e LINQ, purtroppo concluderei che è tempo di cercare un lavoro in cui gli sviluppatori non si paralizzano da soli.

Aggiornamento:

Dal momento che non sembra pensare che quanto sopra risponda alla domanda "è una soluzione alternativa utilizzabile?" Risponderò ora:

No, non lo è. È un abuso di generici e ha troppa "magia" - è persino meno comprensibile rispetto al semplice codice generico e se qualcuno dei tuoi colleghi dovrà approfondire, non sarà in grado di capiscilo.

Il fatto che funzioni e faccia quello che vuoi (nascondere l'uso del generico) è oltre il punto. È opaco e perfino l'uso non è un idioma (dando un "prototipo" alla funzione perché funzioni).

    
risposta data 18.12.2011 - 10:55
fonte
4

Dal momento che non ti permettono di usare tutte le funzionalità della lingua (un linguaggio che, presumo, è stato scelto da loro, non tu,) tutto è permesso. È accettabile? Certo che lo e. Non farei mai una cosa del genere, ma sembra che tu debba farlo. E funzionerà.

Ma se fossi nei tuoi panni andrei fino in fondo con esso: imposterei il livello di compatibilità del compilatore (nelle opzioni del progetto) in modo che i costrutti linguistici che considerano inaccettabili non possano nemmeno essere compilati, il che significherebbe che il l'intero negozio codifica in C # 1.0. E vorrei iniziare a cercare un altro lavoro.

    
risposta data 18.12.2011 - 12:25
fonte
4

Il modo in cui vedo la tua domanda è la seguente:

Should I write code which doesn't follow the standard conventions and will teach people who don't know generics bad habits, or should I use them the way they're intended to be used?

Visto da quella prospettiva, penso che risponda da solo.

In risposta a "Che cosa significa where ?" è possibile inviare una e-mail che rimanda al link spiegando che sebbene MS ha chiaramente indicato il link "Altre versioni", la documentazione delle clausole where di VS2005 è ancora valida.

    
risposta data 18.12.2011 - 15:13
fonte
2

L'introspezione sul fatto che stai rendendo il codice troppo complicato o se è ragionevole aspettarsi che gli altri capiscano e utilizzino il tuo codice è una buona cosa. Tuttavia, su questo particolare snippet

MyDerivedClass instance = null; 
instance = Generate(5, instance); 

Non mi piace. A mio avviso, questo non semplifica il codice. E ovviamente non è più sintetico. Non hai salvato lo sviluppatore dal dover specificare il tipo di classe per la chiamata al metodo generico, ti sei semplicemente spostato dove è specificato. Ad ogni modo, hai esplicitamente dichiarato il tipo. Mi stai anche chiedendo cosa potrebbe fare il metodo con instance , perché lo sto riassegnando, ecc. (Tieni presente che qualcuno potrebbe "rinnovarsi" o avere un'istanza prima della chiamata al metodo. ) Per uno sviluppatore esperto *, questo potrebbe non essere un problema. Per il junior stai cercando di ripararti?

No, opterei per ciò che dovrebbe essere abbastanza semplice da ragionare.

var instance = Generate<MyDerivedClass>(5); 

Sicuramente vuoi rendere il codice facile da leggere, utilizzare e decifrare il più possibile, ma creare la soluzione con sovraccarico con parametri degenerati non è probabilmente la soluzione.

(*) Recentemente sono stato coinvolto nell'aiutare a intervistare candidati per ruoli nella mia attuale squadra. Diciamo solo che gli "sviluppatori esperti" non hanno la stessa esperienza di come tu e io potremmo desiderare e potrebbero credere. Questi sviluppatori con 5, 8, anche 20 anni di esperienza non capirebbero nemmeno il tuo frammento più semplice. Queste sono persone che sono state nel settore per anni, hanno sviluppato C # dal 1.1 o 2.0. Sono anche persone che ancora non riescono a ragionare sui generici, la loro raccolta di scelta è ancora ArrayList, non possono descrivere in modo adeguato meno implementare comportamenti polimorfici, ecc., Non so cosa dire. Forse semplicemente non sono stati spinti ai loro precedenti ruoli. Forse non sono così appassionati di sviluppo o resistenti al cambiamento. Forse sono solo culto del carico. Basti dire che posso simpatizzare con la tua situazione.

    
risposta data 19.12.2011 - 16:29
fonte
1

Penso che non dovresti assolutamente farlo.

Non stai aiutando davvero nessuno, anche se capisco che è quello che stai provando. Ma alla fine, stai ostacolando la comprensione del sistema di tipo statico nascondendo qualcosa di fondamentale. Voglio dire, non è che stiamo parlando di covarianza / controvarianza o di tipi di ordine superiore qui.
Questi sono semplici parametri del primo ordine con vincoli. Questo è qualcosa che ogni programmatore dovrebbe capire. Se non lo fanno, dovrebbero impararlo e non sono disposti a farlo, dovrebbero invece codificare in un linguaggio dinamico (o essere licenziati se me lo chiedi).

Il punto di sistemi di tipo statico è codificare la conoscenza del dominio in semantica linguistica. Più potente è il sistema dei tipi, più difficile è imparare, ma maggiore è la sicurezza che otterrai automaticamente. Questo è un investimento di circa mezza giornata di tutoraggio al massimo, che inizierà a ripagare in poche settimane. Il tuo codice base diventerà più robusto, quindi più flessibile e quindi il costo di risposta alle modifiche dei requisiti e il debug in generale verranno notevolmente ridotti.

Se ritieni di dover fare questo, suppongo che dovresti fare qualcosa del tipo (non sono sicuro di come dovrebbe apparire in C #):

public T Generate<T>(Class<T> theClass, int paramForInstance) where T : MyClass {
    return MyClass.SomeFactoryMethod<T>(paramForInstance);
}
//which should make this possible
var instance = Generate(MyDerivedClass, 5);

Il punto è che stai usando virtualmente i parametri del tipo qui. Una volta che i tuoi colleghi lo accettano, passare a Generate<MyDerivedClass>(5) è solo un piccolo passo per loro, ma un passo da gigante per la tua squadra;)

    
risposta data 19.12.2011 - 13:35
fonte
1

Una cosa che penso tu debba essere consapevole di essere in una "squadra" di sviluppo è che il tuo codice deve essere leggibile e mantenibile dagli altri. Sono d'accordo con le risposte per insegnare e far avanzare la squadra, ma fino a quando ciò non accadrà è necessario attenersi a costrutti che tutti comprendono e con cui è a proprio agio.

    
risposta data 19.12.2011 - 15:38
fonte
0

Il parametro gerneric nel codice non è "fittizio", poiché viene utilizzato come tipo di ritorno. Questo è un modello comune utilizzato anche da Microsoft nel BCL. Esempio trovato in

System.Data.DataRowExtensions

public static T Field<T>(this System.Data.DataRow row, string columnName)
    
risposta data 18.12.2011 - 16:24
fonte

Leggi altre domande sui tag