Esistono generici funzionali e qual è il nome corretto per loro se lo fanno?

6

Considera la seguente classe generica:

public class EntityChangeInfo<EntityType,TEntityKey>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKeyType EntityKey {get;}
}

Qui EntityType definisce univocamente TEntityKeyType . Quindi sarebbe bello avere un tipo di mappa dei tipi:

public class EntityChangeInfo<EntityType,TEntityKey> with map 
  < [ EntityType : Person -> TEntityKeyType : int]
    [ EntityType : Car -> TEntityKeyType : CarIdType ]>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKeyType EntityKey {get;}
}

Un altro esempio è:

 public class Foo<TIn> with map
< [TIn : Person -> TOut1 : string, TOut2 : int, ..., TOutN : double ]
  [TIn : Car -> TOut1 : int, TOut2 :int, ..., TOutN : Price ] >
    {
        TOut1 Prop1 {get;set;}
        TOut2 Prop2 {get;set;}
        ...
        TOutN PropN {get;set;}
    }

La domanda ragionevole: come può essere interpretata dal compilatore? Bene, per me è solo la scorciatoia per due classi strutturalmente simili:

public sealed class Foo<Person>
{
    string Prop1 {get;set;}
    int Prop2 {get;set;}
    ...
    double PropN {get;set;}
}

public sealed class Foo<Car>
{
    int Prop1 {get;set;}
    int Prop2 {get;set;}
    ...
    Price PropN {get;set;}
}

Ma oltre a questo potremmo visualizzare alcuni aggiornamenti di Foo<> :

public class Foo<TIn> with map
    < [TIn : Person -> TOut1 : string, TOut2 : int, ..., TOutN : double ]
      [TIn : Car -> TOut1 : int, TOut2 :int, ..., TOutN : Price ] >
        {
            TOut1 Prop1 {get;set;}
            TOut2 Prop2 {get;set;}
            ...
            TOutN PropN {get;set;}

            public override string ToString()
            {
                 return string.Format("prop1={0}, prop2={1},...propN={N-1},
                                         Prop1, Prop2,...,PropN);
            }
        }

Tutto ciò può sembrare abbastanza superficiale, ma l'idea è venuta quando stavo progettando i messaggi per il nostro sistema. La prima classe. Molti messaggi con la stessa struttura dovrebbero essere discriminati da EntityType .

Quindi la domanda è se tale costrutto esiste in qualsiasi linguaggio di programmazione?

    
posta Pavel Voronin 15.11.2012 - 23:22
fonte

4 risposte

8

Sì, questa funzione esiste in alcuni linguaggi di programmazione.

Ad esempio, in Haskell, questi sono chiamati Dipendenze funzionali (i fondi non sono parte di Haskell 98, ma sono supportato in implementazioni comuni come GHC)

In C ++, puoi ottenere questo tipo di cose con classi di tratti .

    
risposta data 15.11.2012 - 23:39
fonte
1

Bene ... potresti semplicemente chiudere i tipi per comodità:

public class EntityChangeInfo<TEntityType,TEntityKey>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKeyType EntityKey {get;}
}

public class PersonChangeInfo : EntityChangeInfo<Person,int>
{
}

public class CarChangeInfo : EntityChangeInfo<Car, CarIdType>
{
}

Tuttavia, sembra che qualcosa del genere sarebbe più flessibile:

public **interface** IEntityChangeInfo<TEntity,TEntityKey>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKey EntityKey {get;}
    TEntity Entity {get;}
}

Inoltre, questo potrebbe dipendere dalla lingua, ma suggerirei che anche se utilizzi internamente un enum per praticità, NON esponi l'enum nel contratto.

public **interface** IEntityChangeInfo<TEntity,TEntityKey>
{
    int? ChangeTypeId {get;}
    TEntityKey EntityKey {get;}
    TEntity Entity {get;}
}

o

public **interface** IEntityChangeInfo<TEntity,TEntityKey,TChangeType>
{
    TChangeType ChangeType {get;}
    TEntityKey EntityKey {get;}
    TEntity Entity {get;}
}
    
risposta data 16.11.2012 - 00:50
fonte
1

La risposta di John Bartholomew è la corretta esposizione della tecnica a cui ti stai riferendo.

Lasciando questa risposta non corretta qui per un breve periodo per i posteri in quanto è contenuto correlato pertinente. Probabilmente cancellerà domani quando avrai avuto il tempo di rivedere le informazioni nel caso in cui fosse utile per te:)

Esiste una classe di linguaggi funzionali con un concetto correlato, denominata "tipi dipendenti": l'idea è che è possibile creare funzionalità che dipendono da particolari valori di un tipo piuttosto che dal tipo stesso. (questa è la mia descrizione molto limitata del concetto: le persone pazze della matematica possono parlare con questo di più)

Ecco la wikipedia per ulteriori letture, elenca una mano piena di linguaggi che implementano i tipi dipendenti.

Uno dei più grandi usi dei tipi dipendenti, dal momento che li capisco, è per le prove, il che ha senso se ci si pensa ed è simile a quello per cui si sta tentando di usarlo; stai cercando di vincolare i tipi per ottenere funzionalità specifiche nel tuo tipo da un tipo passato a te; i tipi dipendenti funzionano in modo simile ma limitano il livello del valore che è un vincolo molto strong che potresti vedere utile nel contesto di provare che le cose interagiscono in modo rigorosamente definito.

; chiunque abbia più familiarità con il concetto di tipi dipendenti mi corregga se non riesco a capire. È un concetto di altissimo livello e non uno di cui ho esperienza diretta al di là della mia dipendenza dalla lettura di varie lingue, non vorrei dare informazioni errate qui.

    
risposta data 16.11.2012 - 00:26
fonte
-2

Penso che tu stia usando i generici per qualcosa per il quale non sono stati pensati e progettati.

I generici devono consentire al chiamante di creare un tipo specifico dal modello generico. Il tipo generico non dovrebbe mai sapere che tipo di caller inserirà. Può limitare questi tipi, ma non conoscere mai i tipi esatti. Pensa come useresti questi tipi? Non si può passare a qualcos'altro, perché significherebbe che anche qualcos'altro deve essere generico e quindi si ottiene un "creep generico" in cui i tipi generici vengono propagati attraverso la struttura. Ero lì e non è affatto buono.

Quello che stai cercando di ottenere è estremamente simile alla generazione del codice. Puoi usare T4 o qualcosa del genere e generare tutte le classi richieste da un qualche tipo di definizione. Dovresti davvero dimenticare i farmaci generici e pensare in puro OOP. Trova qualcosa che tutti quei messaggi hanno in comune che il sistema di messaggi può usare e implementare una classe concreta per ogni tipo di messaggio. Ciò renderà il design molto più flessibile, perché non sei limitato a due campi e sarà molto più pulito.

    
risposta data 15.11.2012 - 23:39
fonte