Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Reflection Ricorsiva di Oggetti Javascript

Posted by Ricibald on 5th March 2009

Spesso lavorando con javascript ci troviamo una variabile complessa di cui non sappiamo nulla. Sarebbe bello avere un autocompletamento che ci elenchi tutte le funzioni e le proprietà ma gli IDE per ora non ci vengono troppo di aiuto (se ne conoscete qualcuno ditelo!!).

Quindi risulta utile ispezionare la variabile per trovare tutte le proprietà e funzioni che questa variabile dichiara in modo ricorsivo. A questo scopo, riporto il codice che ho scritto che consente di fare questo “sporco lavoro”. Cosa ne pensate? Esiste modo di ottimizzarlo (a parte migliorie di output)?

function TraceMethodsAndProperties(obj) {
	var prefix = "";
	var result = TraceMethodsAndPropertiesRecursion(obj, prefix);
	copyToClipboard(result);
}

function TraceMethodsAndPropertiesRecursion(obj, prefix){
	//alert('gotta:' + prefix);
	var result = "";
	try {
		if(obj != null) {
			for (var s in obj)
			{
				var value = obj[s];
				var key = prefix + s;
				
				result += "---------" + key + '=' + value + ';\n\n'
				var newPrefix = key + '.';
				result += TraceMethodsAndPropertiesRecursion(value, newPrefix);
			}
		}
	} catch(e) {
		// eccezione affogata per il singolo elemento che non consente la scansione: vai al prossimo
	}
	return result;
}

function copyToClipboard(s)
{
	window.clipboardData.setData('Text', s); // solo IE
}

Esempio di utilizzo:

    var persona = getCarloRossi();
    TraceMethodsAndProperties(persona);
    // OUTPUT:
    // ---------Nome=Carlo
    // ---------Cognome=Rossi
    // ---------Indirizzo.Via=via roma
    // ---------Indirizzo.Civico=32
    // ---------Indirizzo.CheckValid=function checkValid(via) { return via != ""; }

Posted in javascript | 2 Comments »

Sincronizzare Oggetti e Controlli Web/Windows In Un Colpo Solo

Posted by Ricibald on 14th August 2008

L’utilizzo dei controlli Web/Windows prevede due fasi:

  • il trasferimento dei dati dall’oggetto ai controlli corrispondenti
  • il trasferimento dei dati dai controlli all’oggetto corrispondente

Come dire:

void loadPage(TextBox txt_nome, Persona persona) {
    txt_nome.Text = persona.Nome;
}

void submitInfo(TextBox txt_nome, Persona persona) {
    persona.Nome = txt_nome.Text;
}

Questo è il classico approccio, ma, come tutte le cose meccaniche che si fanno in informatica, nasconde vari problemi:

  1. il tempo: scrivo le stesse cose due volte. Prima ad andare e poi a tornare…
  2. la consistenza: qualche proprietà potrei dimenticarla e l’oggetto potrebbe non essere aggiornato o potrebbe essere popolato con il valore sbagliato

La cosa ideale sarebbe avere un controllo Web/Windows che consentisse di realizzare il bind a due vie (le due fasi le fa il controllo per noi):

void bind(TextBoxBinded txt_nome, Persona persona) {
    txt_nome.Bind(persona.Nome);
}

Questa “sarebbe” la cosa ideale, ma non è praticabile: come conosciamo il set della proprietà “Nome”? In questo modo non possiamo:

Come passare per parametro i metodi get/set di una proprietà o di un campo, in modo da ottenere il bind a due vie?

Dopo ricerche su internet, miei ragionamenti e varie ed eventuali, le soluzioni possibili sono le seguenti:

  1. Approccio basato su Reflection: la soluzione più immediata, ma molto fragile: per ottenere un oggetto Property dobbiamo passare il nome della proprietà. Tale nome è una semplice stringa: non è pertanto tipizzato in alcun modo ed eventuali modifiche alla proprietà non ci verrebbero segnalate dal compilatore… Con questo approccio ogni modifica alla struttura ad oggetti diventerebbe letteralmente un incubo…
  2. Ogni proprietà implementa un interfaccia specifica: ad esempio IProperty<T>, dove T è il tipo della proprietà. Tale interfaccia avrà metodi get e set che il controllo Web/Windows riconosce. Il metodo bind accetterà quindi solo oggetti di tipo IProperty. L’approccio ha un ulteriore vantaggio: l’interfaccia può essere pensata come wrapper per contenere metainformazioni. Non solo quindi get o set, ma anche informazioni come editabilità, visibilità, nome, …
    Per abilitarla si devono modificare tutte le proprietà in modo che il tipo non sia ad es. String, ma IProperty<String>: questo però provoca una modifica nell’interfaccia della proprietà, e tutti i metodi che prima utilizzavano ad es. persona.Nome.ToUpper non funzioneranno più.
    Una soluzione eccellente stà nel realizzare degli operatori di conversione impliciti da IProperty<String> a String e nell’implementare le stesse identiche funzioni di String in un suo proxy: PropertyString, che implementa IProperty<String> e dichiara le stesse funzioni di String, rigirando tali funzioni al valore String che contiene.
    Con questo approccio si possono trattare a tutti gli effetti gli IProperty<T> come se fossero effettivamente dei T: i client ne possono essere inconsapevoli…
    Si hanno però svantaggi seguenti:

    • si deve aver accesso alla modifica delle proprietà delle classi. Se della struttura ad oggetti non abbiamo il controllo l’unica soluzione che ci rimane per continuare ad usare il nostro approccio è realizzare un Adapter. Una soluzione piuttosto noiosa…
    • si devono implementare tutte le classi che emulano i tipi primitivi: PropertyString, PropertyInt,  PropertyBool, … è anche vero che una volta fatto diventa patrimonio vostro e rimarrà lì con voi…
  3. Approccio basato su Reflection Tipizzata Fortemente: una splendida soluzione basata su LambdaExpression e Generics proposta da Nick Butler. Il segreto è utilizzare i Generics per dichiarare tramite LambdaExpression la proprietà da “bindare”, più o meno in modo simile alla OrderBy di LINQ:
    PropertyInfo prop = typeof(Persona).GetProperty("Nome"); // VECCHIO APPROCCIO: NON TIPIZZATO
    PropertyInfo prop = Instance<Persona>.GetProperty( o => o.Nome);

    Dove avremo:

    public static class Instance<TClass>
    {
        public static PropertyInfo GetProperty<T>(
                              Expression<Func<TClass, T>> m ) 
        {
            LambdaExpression lambda = m;
            Expression bodyExpr = lambda.Body;
            MemberExpression memberExpr = (MemberExpression)bodyExpr;
            MemberInfo memberInfo = memberExpr.Member;
            PropertyInfo propInfo = (PropertyInfo)memberInfo;
            return propInfo;
        }
    }

    Nonostante l’eleganza dell’approccio (specie se combinato con extension method (si veda l’implementazione di TextBoxFor nell’articolo di MSDN), questo ha un punto in svantaggio rispetto al precedente: consente di inserire solo metadati statici tramite attributi. Viceversa, il vantaggio rispetto alla precedente è che non è necessario modificare nulla del codice preesistente e non bisogna implementare i proxy per ogni tipo primitivo

Insomma, ora che sapete tutto manca “solo” di scrivere le vostre versioni custom dei controlli che consentono il bind (consiglio un Decorator…)

Posted in .net | 1 Comment »

Troncare valori Decimali Assimilabili ad Interi: Automatizzare Modifiche di Proprietà in una Classe

Posted by Ricibald on 1st February 2008

Lo so, il titolo dice poco e dice troppo… Cerco ora di spiegarvi la cosa, e credo che possa interessare a tutti gli sviluppatori .NET.

Mi sono trovato con questo problema apparentemente banale:

Dal database mi venivano restituiti valori di tipo Money, che venivano memorizzati come Decimal in una classe. La conversione Money-Decimal si porta dietro 4 cifre decimali, a prescindere dal valore. Vorrei quindi troncare queste cifre quando non serve. Ad esempio, vorrei convertire 12000,0000 in 12000.

Problema semplice, ma come? Considerate che non avevo un solo decimal, ma circa 200 valori memorizzati così. La soluzione immediata è utilizzare (12000.0000m).ToString("F") o Decimal.Truncate(12000.0000m) per troncare le cifre decimali, ma questo dovrei scriverlo 200 volte, e odio fare copia e incolla “sintomo di cattiva programmazione”.

Allora quello che mi serviva era:

Creare un metodo di utilità che mi consentisse di modificare tutte le cifre decimali in tutto il grafo degli oggetti che conteneva il mio oggetto di partenza.

Vorrei dunque creare un metodo come questo:

Bilancio bilancio = ImportBilancio();
PropertyModifier.ApplyToAllOfType<decimal>(bilancio, delegate(decimal number)
{
    decimal numberTruncated = Decimal.Truncate(number);
    Debug.Write(String.Format(" [Troncato: {0} -> {1}]", number.ToString(), numberTruncated.ToString()));
    return numberTruncated;
});

Riporto quindi la classe che consente questa utilissima funzione, per chiunque ne avesse bisogno:

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Collections;

namespace PropertyModifier
{
public class PropertyModifier
{
public delegate T MethodModifier(T t);

private static BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

public static void ApplyToAllOfType(object obj, MethodModifier modifier)
{
ApplyToAllOfType(obj, modifier, 0, true);
}

private static void ApplyToAllOfType(object obj, MethodModifier modifier, int indent, bool printCurrent)
{
if (obj == null)
return;

Type objType = obj.GetType();

if (printCurrent)
{
DebugWriteNode(objType.Name, indent);
Debug.WriteLine(“”); // vai a capo
}

/* Scandisci proprieta’ */
foreach (PropertyInfo prop in objType.GetProperties(flags))
{
/* Se e’ leggibile e non e’ indexed, ottieni valore */
if (prop.CanRead && prop.CanWrite && prop.GetGetMethod().GetParameters().Length == 0)
{
object propValue = prop.GetValue(obj, null);
if (propValue != null && !propValue.Equals(obj)) // previene cicli
{
DebugWriteNode(String.Format(“p:{0}={1}”,prop.Name, propValue), indent);
if (propValue is T1)
{
object modifiedValue = modifier((T1)propValue);
prop.SetValue(obj, modifiedValue, null);
}
Debug.WriteLine(“”); // vai a capo
ApplyToAllOfType(propValue, modifier, indent + 1, false);
}
}
}

/* Scandisci campi */
foreach (FieldInfo field in objType.GetFields(flags))
{
if (!field.IsInitOnly && !field.IsLiteral)
{
object fieldValue = field.GetValue(obj);
if (fieldValue != null && !fieldValue.Equals(obj)) // previene cicli
{
DebugWriteNode(String.Format(“f:{0}={1}”, field.Name, fieldValue), indent);
if (fieldValue is T1)
{
object modifiedValue = modifier((T1)fieldValue);
field.SetValue(obj, modifiedValue);
}
Debug.WriteLine(“”); // vai a capo
ApplyToAllOfType(fieldValue, modifier, indent + 1, false);
}
}
}

/* Se ho un elemento enumerabile, prendi gli elementi */
if (obj is IEnumerable)
{
IEnumerable enumerableObj = (IEnumerable)obj;
int currElement = 1;
foreach (object childObj in enumerableObj)
{
DebugWriteNode(String.Format(“{0}:{1}={2}”, currElement++, objType.Name, childObj), indent);
Debug.WriteLine(“”); // vai a capo
ApplyToAllOfType(childObj, modifier, indent + 1, false);
}
}
}

private static void DebugWriteNode(string nameToPrint, int indent)
{
for (int i = 0; i < indent; i++) { Debug.Write("| "); } Debug.Write("+ " + nameToPrint); } } } [/sourcecode]

Posted in .net | 2 Comments »

Creare un TreeView da un Oggetto di una Qualunque Classe

Posted by Ricibald on 31st January 2008

Molto utile il seguente progetto:

Object Hierarchical Data Source

Praticamente è un Hierarchical Data Source che si può associare a controlli come TreeView, Menu, SiteMapNavigation, … ma che si scandisce, tramite reflection, la classe dell’oggetto passato in modo ricorsivo per popolare il controllo gerarchico specificato.

Se quindi la classe è sufficientemente descrittiva ed è “piena di roba”, il ché comporterebbe una pagina aspx “piena di controlli”, risulta conveniente utilizzare invece questo approccio e generare la pagina dinamicamente in un TreeView.

Posted in .net | No Comments »