Programming Languages Hacks

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

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

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

Posted by Ricibald on February 1st, 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]

Leave a Reply

You must be logged in to post a comment.