deep copying objects in C#

C# — Tags :, , , — admin @ 21:26

One of the fastest ways to deep copy an object is to serialize it to a binary stream and unserialize it to a new object, in that matter:

  1.        /// <summary>
  2.         /// Creates a deep copy of a serializable object
  3.         /// </summary>
  4.         /// <typeparam name="T">Any type</typeparam>
  5.         /// <param name="serializableObject">serializable object</param>
  6.         /// <returns>cloned object</returns>
  7.         public static T CloneOf<T>(T serializableObject)
  8.         {
  9.             object objCopy = null;
  10.             MemoryStream stream = new MemoryStream();
  11.             BinaryFormatter binFormatter = new BinaryFormatter();
  12.             binFormatter.Serialize(stream, serializableObject);
  13.             stream.Position = 0;
  14.             objCopy = (T) binFormatter.Deserialize(stream);
  15.             stream.Close();
  16.             return (T) objCopy;
  17.         }
  18.  

Playing with winforms textbox border color.

Non classé — Tags :, , , — admin @ 20:12

This is a small hack class that adds a set color for input area borders (textbox, richtextbox, combos, etc.) Here is the result:

Screenshot

Screenshot

It all holds up in a single file:

  1.  
  2.     /// <summary>
  3.     /// This class adds border to input elements similar to Chrome
  4.     /// </summary>
  5.     public class FormBorderizer
  6.     {
  7.         /** PRIVATE MEMBERS **/
  8.         private Label m_lblBorder;                      // label used for borders
  9.         private static Color BORDER_COLOR = Color.Gold; // Border color
  10.         private static int BORDER_WIDTH = 2;            // Border width
  11.         private static Color BACK_COLOR = Color.AliceBlue;       // Back color
  12.  
  13.         /** CONTRUCTORS **/
  14.         /// <summary>
  15.         /// Constructor, adds borders to input areas
  16.         /// </summary>
  17.         /// <param name="Control.ControlCollection">collection of controls to parse</param>
  18.         public FormBorderizer(Control.ControlCollection controlCollection)
  19.         {
  20.             InitializeBorder(controlCollection);
  21.             AddBorder(controlCollection);
  22.         }
  23.  
  24.         /** METHODS **/
  25.  
  26.         /// <summary>
  27.         /// Initializes the border control
  28.         /// </summary>
  29.         /// <param name="controlCollection">collection</param>
  30.         private void InitializeBorder(Control.ControlCollection controlCollection)
  31.         {
  32.             m_lblBorder = new Label();
  33.             m_lblBorder.BackColor = Color.Gold;
  34.             m_lblBorder.Visible = false;
  35.             controlCollection.Add(m_lblBorder);
  36.             m_lblBorder.SendToBack();
  37.         }
  38.  
  39.         /// <summary>
  40.         /// Adds a colored border to a collection of controls
  41.         /// </summary>
  42.         /// <param name="controlCollection">target collection</param>
  43.         private void AddBorder(Control.ControlCollection controlCollection)
  44.         {
  45.             foreach (Control c in controlCollection)
  46.             {
  47.                 // generate event handlers for input areas
  48.                 if (IsInputControl(c))
  49.                 {
  50.                     c.Enter += new EventHandler(c_Enter);
  51.                     c.Leave += new EventHandler(c_Leave);
  52.                 }
  53.                 else if (c is Panel)
  54.                 {
  55.                     new FormBorderizer(c.Controls);
  56.                 }
  57.                 else if (c is TabControl)
  58.                 {
  59.                     TabControl tc = (TabControl)c;
  60.                     foreach (TabPage tp in tc.TabPages)
  61.                     {
  62.                         new FormBorderizer(tp.Controls);
  63.                     }
  64.                 }
  65.             }
  66.         }
  67.  
  68.         /// <summary>
  69.         /// Checks whether this control should hold a border or not
  70.         /// </summary>
  71.         /// <param name="c">target control</param>
  72.         /// <returns>true or false</returns>
  73.         private bool IsInputControl(Control c)
  74.         {
  75.             return (c is TextBox || c is ListBox || c is ComboBox || c is RichTextBox || c is MaskedTextBox);
  76.         }
  77.  
  78.         /** EVENTS **/
  79.         /// <summary>
  80.         /// Event occuring when the user leaves an input control
  81.         /// </summary>
  82.         private void c_Leave(object sender, EventArgs e)
  83.         {
  84.             m_lblBorder.Visible = false;
  85.             Control ctrl = (Control)sender;
  86.             ctrl.BackColor = Color.White;
  87.            
  88.         }
  89.  
  90.         /// <summary>
  91.         /// Event occuring when the user enters an input control
  92.         /// </summary>
  93.         private void c_Enter(object sender, EventArgs e)
  94.         {
  95.             Control ctrl = (Control)sender;
  96.             WrapControl(ctrl);
  97.             m_lblBorder.Visible = true;
  98.             m_lblBorder.Anchor = ctrl.Anchor;
  99.         }
  100.  
  101.         /// <summary>
  102.         /// Wraps the border around the control
  103.         /// </summary>
  104.         /// <param name="control"></param>
  105.         private void WrapControl(Control control)
  106.         {
  107.             m_lblBorder.Top = control.Top - BORDER_WIDTH;
  108.             m_lblBorder.Left = control.Left - BORDER_WIDTH;
  109.             m_lblBorder.Width = control.Width + 2 * BORDER_WIDTH;
  110.             m_lblBorder.Height = control.Height + 2 * BORDER_WIDTH;
  111.             control.BackColor = BACK_COLOR;
  112.         }
  113.  
  114.     }
  115.  

To call it, simply create an instance of FormBorderizer (such an awful name!!) and initialize it with a form / panel control collection.
Ex:

  1.    public partial class Form1 : Form
  2.     {
  3.         public Form1()
  4.         {
  5.             InitializeComponent();
  6.             new FormBorderizer(this.Controls);
  7.         }
  8.  
  9.     }
  10.  
  11.  

Winforms flicker-free forms.

C/C++, Non classé — Tags :, , — admin @ 0:12

Ever had those flickers in your 50+ component forms?

Trying to play with SuspendLayout / ResumeLayout didn’t help? That’s because it only suspends the automatic layout, triggered by the Anchor and Dock properties.

Setting double-buffering to true didn’t help either? That’s because it only suppresses flicker on individual controls: a label, a button and so on…

Setting the OptimizedDoubleBuffer flag to true? Nope, no changes…

After struggling for many hours trying to eliminate a flicker that was occuring on my application form, I finally found a solution on msdn:

It’s called compositing double-buffering and it’s simply 7 lines of code put in somewhere in your form code:

  1.  
  2. protected override CreateParams CreateParams {
  3.   get {
  4.     CreateParams cp = base.CreateParams;
  5.     cp.ExStyle |= 0×02000000;
  6.     return cp;
  7.   }
  8. }

Explanation from nobugz:

I discovered a new Windows style in the SDK header files, available for Windows XP and (presumably) Vista: WS_EX_COMPOSITED. With that style turned on for your form, Windows XP does double-buffering on the form and all its child controls

nobugz is the man…

Java foreach.

Java — Tags :, , — admin @ 17:36

Java 5 got a bit closer to its twin C# by adding the possibility of directly accessing entities of a list or collection through its own “foreach” functionality :

C# :

  1. foreach(type var in arr){
  2.   // implement body
  3. }

Java :

  1. for (type var : arr) {
  2.     // implement body
  3. }

List.Find() use of delegates

C/C++ — Tags : — admin @ 22:02

Delegates make it easier to find stuff in generic lists.
Let’s consider the following simple class:

  1. Public Class Person{
  2.   private string m_name;
  3.   private int m_age;
  4.  
  5.   // .Net3.0 syntax only.
  6.   public string Name{get;set}
  7.   public int Age{get;set}
  8.  
  9.   public Person(string name, int age){
  10.     m_name = name;
  11.     m_age = age;
  12.   }

Instanciating :

  1. List<Person> lstPpl = new List<Person>();
  2. lstPpl.Add(new Person("Christian", 1));
  3. lstPpl.Add(new Person("Noah", 0.3));

We can easily find Noah:

  1. Person myson = lstPpl.Find(delegate(Person p) { return "Noah" == p.Name; });

Encrypted binary serialization

C/C++ — Tags :, — admin @ 0:18

For re-use: a small class that does encryption and binary serialization:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.Runtime.Serialization.Formatters.Binary;
  6. using System.Security.Cryptography;
  7. using System.Windows.Forms;
  8.  
  9. namespace MyNamespace
  10. {
  11.     class Tools
  12.     {
  13.         // change me…
  14.         private static string m_encryptionKey = "password";
  15.  
  16.         public static byte[] Encrypt(byte[] plainData, string sKey)
  17.         {
  18.             DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
  19.             DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
  20.             DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
  21.             ICryptoTransform desencrypt = DES.CreateEncryptor();
  22.             byte[] encryptedData = desencrypt.TransformFinalBlock(plainData, 0, plainData.Length);
  23.             return encryptedData;
  24.         }
  25.  
  26.         public static byte[] Decrypt(byte[] encryptedData, string sKey)
  27.         {
  28.             DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
  29.             DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
  30.             DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
  31.             ICryptoTransform desDecrypt = DES.CreateDecryptor();
  32.             byte[] decryptedData = desDecrypt.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
  33.             return decryptedData;
  34.         }
  35.  
  36.         public static void SaveObjectToFile(object obj, string path){
  37.             try
  38.             {
  39.                 MemoryStream memStream = new MemoryStream();
  40.                 BinaryFormatter binFormatter = new BinaryFormatter();
  41.                 binFormatter.Serialize(memStream, obj);
  42.                 byte[] encryptedBytes = Encrypt(memStream.ToArray(), m_encryptionKey);
  43.                 memStream.Close();
  44.                 Stream streamToFile = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
  45.                 streamToFile.Write(encryptedBytes, 0, encryptedBytes.Length);
  46.                 streamToFile.Flush();
  47.                 streamToFile.Close();
  48.             }
  49.             catch (Exception e)
  50.             {
  51.                 MessageBox.Show(e.Message);
  52.             }
  53.         }
  54.  
  55.         public static object LoadObjectFromFile(string path)
  56.         {
  57.             try
  58.             {
  59.  
  60.                 Stream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  61.                 byte[] encryptedObj = new byte[fileStream.Length];
  62.                 fileStream.Read(encryptedObj, 0, (int)encryptedObj.Length);
  63.                 MemoryStream memStream = new MemoryStream(Decrypt(encryptedObj, m_encryptionKey));
  64.                 BinaryFormatter binFormatter = new BinaryFormatter();
  65.                 object decryptedObj = binFormatter.Deserialize(memStream);
  66.                 memStream.Close();
  67.                 fileStream.Close();
  68.                 return decryptedObj;
  69.             }
  70.             catch (Exception e)
  71.             {
  72.                 MessageBox.Show(e.Message);
  73.             }
  74.             return null;
  75.         }
  76.     }
  77. }

Ces longs raccourcis

C/C++ — Tags :, , — admin @ 9:58

Certains raccourcis peuvent parfois ralonger certaines routes. Par example, il est souvent requis d’échanger deux variables entre elles. Pour peu que cet échange doive avoir lieu au sein d’une boucle, disons pour un affichage fluide par ex., on va chercher à en optimiser l’échange.

De manière logique, on pense de suite à utiliser une variable intermédiaire :

  1. void main()
  2. {
  3.    int a = 0;
  4.    int b = 1;
  5.    int c;
  6.  
  7.    // swap utilisant une 3e variable
  8.    c = a;
  9.    a = b;
  10.    b = c;
  11. }

Cette méthode a beau avoir certains défauts, elle est en tout cas très clair.

Il y a pourtant plus court à écrire :

  1. void main()
  2. {
  3.    int a = 0;
  4.    int b = 1;
  5.  
  6.    // en une ligne!
  7.    a+=b-=a=b-a;
  8. }

Ou du moins c’est ce que l’on pourrait croire… Regardons le code assembleur généré par les deux corps de programmes précédents:

Swap à 3 variables :

  1. push        edi                         ; preparer de la place
  2. push        esi                         ; pour 3 variables
  3. push        ebx  
  4. cmp         dword ptr ds:[00312E08h],0
  5. je          00000011
  6. call        78ACB4AF
  7. xor         esi,esi                     ; a = 0
  8. xor         edi,edi                     ; b = 0
  9. xor         ebx,ebx                     ; c = 0
  10. xor         esi,esi                     ; a = 0
  11. mov         edi,1                       ; b = 1
  12. mov         ebx,esi                     ; c = a
  13. mov         esi,edi                     ; a = b
  14. mov         edi,ebx                     ; b = c

Swap en une ligne :

  1. push        edi                         ; preparer de la place
  2. push        esi                         ; pour 2 variables
  3. cmp         dword ptr ds:[003F2E08h],0
  4. je          00000010
  5. call        7963B4AF
  6. xor         esi,esi                     ; a = 0
  7. xor         edi,edi                     ; b = 0
  8. xor         esi,esi                     ; a = 0
  9. mov         edi,1                       ; b = 1
  10. mov         eax,edi                     ; eax = reg. temporaire
  11. sub         eax,esi                     ; eax = b - a
  12. mov         esi,eax                     ; a = b - a
  13. sub         edi,esi                     ; b = b - a
  14. add         esi,edi                     ; a = a + b

On économise peut-être du tps en n’allouant pas de place pour une troisième variable, on le paye plus tard. Au final, le swap en une seule ligne prendra légèrement plus de temps que le swap sur 3 lignes. Plus important encore, le swap en une ligne est beaucoup moins lisible… Autant donc travailler clairement!!

Remarque :
Il existe une version optimale d’un échange de deux variables, détaillée ici : http://en.wikipedia.org/wiki/XOR_swap . Certains diront que cette version n’est pas entièrement portable… Mais ca reste à prouver, je l’ai vu tourner un peu partout… La technique consiste à utiliser la commande XOR qui est plus rapide que la commande MOV, comme ceci:

  1. void main()
  2. {
  3.    int a = 0;
  4.    int b = 1;
  5.  
  6.    // avec des Xor :
  7.    a = a ^ b;
  8.    b = a ^ b;
  9.    a = a ^ b;
  10. }

Ce qui donne :

  1. push        edi  
  2. push        esi  
  3. cmp         dword ptr ds:[00212E08h],0
  4. je          00000010
  5. call        7974B4AF
  6. xor         esi,esi
  7. xor         edi,edi
  8. xor         esi,esi
  9. mov         edi,1
  10. xor         esi,edi
  11. xor         edi,esi
  12. xor         esi,edi

Encore une fois, la lisibilité n’est pas optimale, à moins d’être habitué à faire des XOR!

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2012 Random namespace | powered by WordPress with Barecity