Pagina 2 di 3 primaprima 1 2 3 ultimoultimo
Visualizzazione dei risultati da 11 a 20 su 21
  1. #11
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    In questo caso dovresti fare in questo modo :

    codice:
    public class FaceT : IFace
        {
            public int[] nodes { get; set; }
            public FaceT()
            {
                nodes = new int[4];
                nodes[0] = 0;
                nodes[1] = 2;
                nodes[2] = 4;
                nodes[3] = 6;
            }
        }
    
    
        public class FaceH : IFace
        {
            public int[] nodes { get; set; }
            public FaceH()
            {
                nodes = new int[4];
                nodes[0] = 1;
                nodes[1] = 3;
                nodes[2] = 5;
                nodes[3] = 7;
    
    
            }
        }
    
    
        public interface IFace
        {
            int[] nodes { get; set; }
        }
    
    
        public class Normal<T> where T : IFace, new()
        {
            public T[] faces { get; set; }
            public Normal()
            {
                faces = new T[6];
                faces[0] = new T();
                faces[1] = new T();
                faces[2] = new T();
                faces[3] = new T();
                faces[4] = new T();
                faces[5] = new T();
            }
        }
    Praticamente crei una classe generica (normal<T>) dove T può essere un derivato di IFace, mentre FaceH e FaceT dovranno ereditare da IFace, in questo modo potrai accedere a nodes (ricorda di usare sempre i get e set nelle proprietà, non usare campi), diversamente potrai accedere solo a faces (di Normal<T>), ma lo vedrai come object, quindi non vedrai nodes.
    A questo punto il metodo diventa questo :
    codice:
    public int Sum<T>(Normal<T> faces) where T : IFace, new()
            {
                return faces.faces[0].nodes.Sum();
            }
    e lo usi così :

    codice:
    vat tot = this.Sum(new Normal<FaceT>());//tot=12 (0+2+4+6)
    //oppure
    tot = this.Sum(new Normal<FaceH>());//tot = 16 (1+3+5+7)
    Come ti dicevo prima, puoi anche non usare IFace, ma in quel caso non avrai accesso a nodes, per ovviare a questo dovresti poi leggere il tipo di faces (della Normal<T>) e fare la conversione, oppure se sei certo che sia sempre un tipo che contiene una proprietà di nome nodes (dello stesso tipo) puoi convertire a dynamic, ma in quel caso perdi il supporto dell'intellisense ed inoltre non stai usando la tipizzazione forte. Ti consiglio di usarla l'interfaccia IFace, il codice sarà molto meno incline ad errori.

    Volendo si poteva semplificare meglio, ma siccome credo che sia solo un esempio non ho semplificato, rischiavo di farti prendere fischi per fiaschi!

    Inoltre in questo caso, visto che tanto FaceT e FaceH non derivano da nulla, al posto di un interface puoi usare una classe (Face) che ha già dei metodi/proprietà di base comuni a tutti i tipi Face*, ma dipende dai casi.
    Ultima modifica di U235; 12-01-2014 a 00:31

  2. #12
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308


    mamma mia c'è da studiare 1 anno solo per non duplicare una funzione... tutto questo però è bellissimo, mi ci metterei pure ad applicarlo però il progetto è terribilmente più complicato dell'esempio che ho fatto (esistono 6 strutture Normal e 27 strutture sferiche) e le funzioni "incriminate" tipo Sum sono 5 e non una sola e per di più alcune di queste ne richiamano altre....) e sono sicuro che finirei per perdermi. In fondo fin qui funziona tutto molto bene.


    Invece sono molto interessato alle ultime 2 righe perchè è quello che ho tentato di fare: mi creo una classe "madre" (non capisco perchè nella OOP si parla di classe "padre": è contro natura)


    public class Face

    {
    public int[] nodes;
    }

    e faccio ereditare le altre da questa

    public class FaceT : Face

    public class FaceH : Face

    per poi scrivere

    public static int Sum<T>(T face) where T : Face

    Però succede che:

    1) Se scrivo il costruttore di Face i costruttori di FaceT e FaceH non valgono più e sono adombrati da quello di Face;
    2) Se faccio il furbo e scrivo un costruttore Face() che non fa nulla allora la somma dei nodi in qualunque faccia mi dà sempre zero;
    3) Se faccio ancora di più il furbo e non scrivo il costruttore di Face il compilatore mi dà un bel NullReference cioè FaceT e FaceH non riescono (ovviamente) ad istanziare quindi tanto furbo non sono stato.
    Qui c'è un problema di shadowing ed overrides....
    Ultima modifica di escocat; 12-01-2014 a 11:08

  3. #13
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    237
    Ciao.
    Scusate se mi intrometto, ma stavo seguendo la discussione perché la trovo molto interessante ed esemplificativa dei casi in cui si struttura il codice con ereditarietà e le interfacce..
    Vi chiedo solo una cosa (sperando di non complicare troppo le cose), perché è una "sintassi" che non mi è mai capitato di vedere.
    Il codice (tradotto in VB.NET perché lo conosco meglio)
    codice:
    Public Class Normal(Of T As {IFace, New})
    	Public Property faces() As T()
    		Get
    			Return m_faces
    		End Get
    		Set
    			m_faces = Value
    		End Set
    	End Property
    	Private m_faces As T()
    	Public Sub New()
    		faces = New T(5) {}
    		faces(0) = New T()
    		faces(1) = New T()
    		faces(2) = New T()
    		faces(3) = New T()
    		faces(4) = New T()
    		faces(5) = New T()
    	End Sub
    End Class
    Crea una classe normal, ma all'atto della dichiarazione di classe, cosa vuol dire ?
    codice:
    Public Class Normal(Of T As {IFace, New})
    La classe Normal, "implementa" IFace?, quel Of T fa riferimento ai generici, giusto? e quindi? e quel New tra {}, cosa significa? Il resto è chiaro.
    Grazie, e se rispondermi significa portare la discussione O.T. allora lasciate pure stare.
    Ciao!

  4. #14
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    Ciao escocat,
    ok, riguardo alla classe hai ragione, ma anche il padre lascia il suo DNA , da ora la chiamiamo genitore la classe base così non discriminiamo le donne!
    Scherzi a parte, bisogna stare attenti a non abusare dei generics, essi si dovrebbero adottare quando ci rendono migliore o più semplice la scrittura di codice. Spesso appena si inizia ad utilizzarli si tende ad abusare dei generics, e ancora più spesso vengono utilizzati anche dove non servono.
    Ad esempio, per come mi hai descritto la situazione, credo ti sarebbe utile fare in modo che i vari Face* derivino tutte da una tipo (interface o class) genitore (Face) :

    codice:
    public class FaceT : Face
        {
            public FaceT()
            {
                nodes = new int[4];
                nodes[0] = 0;
                nodes[1] = 2;
                nodes[2] = 4;
                nodes[3] = 6;
            }
        }
    
    
        public class FaceH : Face
        {
            public FaceH()
            {
                nodes = new int[4];
                nodes[0] = 1;
                nodes[1] = 3;
                nodes[2] = 5;
                nodes[3] = 7;
    
    
            }
        }
    
    
        public class Face
        {
            public int[] nodes { get; set; }
        }
    
    ....
    static void Main(string[] args)
            {
                List<Face> faces = new List<Face>();
                faces.Add(new FaceH());
                faces.Add(new FaceT());
                var sum = faces.Sum(s => s.nodes.Sum());//28 somma totale tutti i nodi di tutte le liste
    
    
                var totH = faces.OfType<FaceH>().Sum(s => s.nodes.Sum());//16 somma nodi delle liste di tipo FaceH
                var totT = faces.OfType<FaceT>().Sum(s => s.nodes.Sum());//12 somma nodi delle liste di tipo FaceT
    
    
                var totH2 = Sum<FaceH>(faces);//16 somma nodi delle liste di tipo FaceH
                var totT2 = Sum<FaceT>(faces);//12 somma nodi delle liste di tipo FaceT
    
    
                var sum2 = Sum<Face>(faces);//28 somma totale tutti i nodi di tutte le liste
            }
    
    
            public static int Sum<T>(IList<Face> faces) where T : Face
            {
                int result = 0;
                result = faces.OfType<T>().Sum(s => s.nodes.Sum());
                return result;
            }
    Chiaramente per fare una cosa fatta bene si dovrebbe conoscere il progetto, dovresti provare a fare esempi più concreti, nel senso che solo nel reale utilizzo sai se serve davvero usare metodi e classi generiche (oltre a quelle che già esistono). In questo caso dovrebbe bastare l'ereditarietà, senza generics, ma se andiamo oltre la somma di interi andrebbe "ragionata" sul reale caso d'uso.

  5. #15
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    Quote Originariamente inviata da renygade Visualizza il messaggio
    Ciao.
    Scusate se mi intrometto, ma stavo seguendo la discussione perché la trovo molto interessante ed esemplificativa dei casi in cui si struttura il codice con ereditarietà e le interfacce..
    Vi chiedo solo una cosa (sperando di non complicare troppo le cose), perché è una "sintassi" che non mi è mai capitato di vedere.
    Il codice (tradotto in VB.NET perché lo conosco meglio)
    codice:
    Public Class Normal(Of T As {IFace, New})
        Public Property faces() As T()
            Get
                Return m_faces
            End Get
            Set
                m_faces = Value
            End Set
        End Property
        Private m_faces As T()
        Public Sub New()
            faces = New T(5) {}
            faces(0) = New T()
            faces(1) = New T()
            faces(2) = New T()
            faces(3) = New T()
            faces(4) = New T()
            faces(5) = New T()
        End Sub
    End Class
    Crea una classe normal, ma all'atto della dichiarazione di classe, cosa vuol dire ?
    codice:
    Public Class Normal(Of T As {IFace, New})
    La classe Normal, "implementa" IFace?, quel Of T fa riferimento ai generici, giusto? e quindi? e quel New tra {}, cosa significa? Il resto è chiaro.
    Grazie, e se rispondermi significa portare la discussione O.T. allora lasciate pure stare.
    Ciao!
    Ciao, è una discussione aperta a tutti, nessuna intromissione! Inoltre non credo la tua domanda sia OT, e qualora lo fosse ci penseranno i moderatori, ma ripeto : non credo sia questo il caso...

    Allora... la classe Normal possiede un tipo (attenzione : Normal<T> non è di tipo IFace, non implementa lui IFace, ma lo fa T) non definito in compilazione (T), ma questo tipo deve necessariamente essere derivato dall'interfaccia IFace (quindi le classi che derivano da IFace devono implementare int[] nodes), mentre il New() indica che T si tratta di un tipo che possiede un costruttore senza parametri. Aggiungendo New il compilatore da per scontato che T possiede il costruttore senza parametri, quindi ti consente di utilizzare una sintassi simile a questa : T mioT = new T(), senza questa key non potresti creare un istanza di T, in quanto il compilatore non sa se esiste realmente in T un costruttore senza parametri.

  6. #16
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    237
    Quote Originariamente inviata da U235 Visualizza il messaggio
    Allora... la classe Normal possiede un tipo (attenzione : Normal<T> non è di tipo IFace, non implementa lui IFace, ma lo fa T) non definito in compilazione (T)
    Ok, intanto grazie. Ci sono quasi.. T è il generics giusto?.
    Quindi dici: "L'oggetto generico T implementa IFace e ha un costruttore New() privo di parametri.Ok.
    E' poi? Il passaggio della dichiarazione della Classe Normal? Mettento Normal(of T) vuol dire che è una classe "generica"?. (forse mi manca qualche passaggio di teoria...

  7. #17
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Ora usiamo i delegate e le lambda?
    No, grazie, hai ragione tu: mai usare i generics se proprio non sono necessari.
    Certo che avremmo risolto subito il problema se i costruttori di FaceT e FaceH non fossero offuscati dal costruttore di Face.... mi risulta che gli overrides non valgono per i costruttori, ma non c'è qualche condono? E se scrivessi Face come classe astratta? Non so sto dicendo cose turpi non conosco ancora a fondo le leggi di Mendel della programmazione OP. Cosa si può fare continuando sulla linea dell'eredità da Face senza far intervenire delegate e IList?


    P.S. Ti ringrazio di aver risposto tu a Renegade: io con ho capito un tubo di quello che ha scritto.

  8. #18
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    Quote Originariamente inviata da escocat Visualizza il messaggio
    Ora usiamo i delegate e le lambda?
    No, grazie, hai ragione tu: mai usare i generics se proprio non sono necessari.
    Certo che avremmo risolto subito il problema se i costruttori di FaceT e FaceH non fossero offuscati dal costruttore di Face.... mi risulta che gli overrides non valgono per i costruttori, ma non c'è qualche condono? E se scrivessi Face come classe astratta? Non so sto dicendo cose turpi non conosco ancora a fondo le leggi di Mendel della programmazione OP. Cosa si può fare continuando sulla linea dell'eredità da Face senza far intervenire delegate e IList?


    P.S. Ti ringrazio di aver risposto tu a Renegade: io con ho capito un tubo di quello che ha scritto.
    Non ho capito, il discorso dei costruttori offuscati... che intendi? quando vengono "offuscati" dalla base?

    codice:
    Face f = new FaceH();
    var totale = f.nodes.Sum();//totale 16, ovvero è stato chiamato il costruttore corretto...

  9. #19
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    No, intendevo che se Face ha un costruttore e

    FaceT : Face

    ne ha un altro, quando istanzio FaceT non costruisce new FaceT() ma new Face()!

  10. #20
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,539
    Quote Originariamente inviata da escocat Visualizza il messaggio
    No, intendevo che se Face ha un costruttore e

    FaceT : Face

    ne ha un altro, quando istanzio FaceT non costruisce new FaceT() ma new Face()!
    Purtroppo ti devo contraddire... quando crei un istanza di una classe derivata, prima viene chiamato il costruttore della classe base, poi quello della classe derivata. Se invece il tuo problema è fare in modo che non venga eseguito il codice del costruttore di base (in questo caso c'è già un problema di logica probabilmente) allora potresti ad esempio fare così :

    codice:
    public class FaceT : Face
        {
            public FaceT()
                : base(false)
            {
                Console.WriteLine("in FaceT");
                nodes = new int[4];
                nodes[0] = 0;
                nodes[1] = 2;
                nodes[2] = 4;
                nodes[3] = 6;
            }
        }
    
    
        public class FaceH : Face
        {
            public FaceH()
                : base(false)
            {
                Console.WriteLine("in FaceH");
                nodes = new int[4];
                nodes[0] = 1;
                nodes[1] = 3;
                nodes[2] = 5;
                nodes[3] = 7;
            }
        }
        
        public class Face
        {
            public Face(bool generaArray=true) 
            {
                if (generaArray)
                {
                    Console.WriteLine("in Face");
                    nodes = new int[8];
                    nodes[0] = 1;
                    nodes[1] = 3;
                    nodes[2] = 5;
                    nodes[3] = 7;
                    nodes[4] = 0;
                    nodes[5] = 2;
                    nodes[6] = 4;
                    nodes[7] = 6;
                }
            }
            public int[] nodes { get; set; }
        }
    in pratica aggiungo un parametro bool al costruttore della base, che di default è a true (quindi funziona come costruttore senza parametri, ma con il valore true per eseguire il codice, in questo modo quando chiami new Face() il codice è eseguito automaticamente), ed in base al valore di quest'ultimo eseguo o no il codice del costruttore, in questo modo quando viene chiamato il costruttore senza parametri delle classi derivate, passo il parametro false alla classe base, così non sarà eseguito il codice dentro l'if.

    ora se fai :
    codice:
    var face = new Face()//ottieni 8 int (pari e dispari)
    var faceT = new FaceT()//ottieni 4 int (pari)
    var faceH = new FaceH()//ottieni 4 int (dispari)
    ovviamente in ogni caso otterresti lo stesso risultato (sia con false che con true passato alla base) in quanto il costruttore della derivata riscrive l'array, ma era solo per farti capire il meccanismo.
    Ultima modifica di U235; 12-01-2014 a 21:27

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.