Toutoune DevZone

.NET (C#)
Étendre l'Intellisense d'un fichier de configuration

Vous venez de créer votre propre section de configuration et vous aimeriez bien la rendre un peu plus sexy ? Quoi de mieux qu'un peu d'Intellisense ?

Tout commence par un schéma XML (XSD)...

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified"
           vs:helpNamespace="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <xs:element name="maSection">
      ...
    </xs:element>
</xs:schema>

Mon objectif n'étant pas d'expliquer la syntaxe des fichiers XSD, je vous invite à aller jeter un oeil du côté de site comme http://www.w3schools.com/schema/.

Ça y est vous avez créer un schéma XSD qui correspond à votre nouvelle section de config ! Copier le à l'adresse suivante :
C:\Program Files\Microsoft Visual Studio[votre version]\Xml\Schemas\

Soit :

  • "C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas" pour Visual Studio 2008.
  • "C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas" pour Visual Studio 2005.

Vous remarquerez que ce dossier contient un fichier "catalog.XML" qui sert de manifest à Visual Studio. Pour que notre fichier XSD soit pris en compte, il est indispensable d'y faire référence ici.
L'objectif est d'associer aux fichiers "*.config" notre schéma, on va donc rajouter un noeud <Association extension="config" ... /> comme suit :

<SchemaCatalog xmlns="http://schemas.microsoft.com/xsd/catalog">
   ...
   <Association extension="config" schema="%InstallRoot%/xml/schemas/cdc.xsd" />
</SchemaCatalog>

Une dernière chose à faire, redémarrez Visual Studio pour que tout ça soit pris en compte. Et voilà !

Posted: avr. 15 2008, 05:11 par Toutoune_31 | avec 1 comment(s)
Classé sous :
Benchmark de code C#

Voici un petit utilitaire que j'ai codé y a un petit moment et qui permet facilement de tester les perfs de bouts de code C#.
N'hésitez pas à y apporter des améliorations et à me faire un petit retour ;)
Vous avez à votre dispo le code complet dans le ZIP en fichier joint.

C'est cette petite appli console qui m'avait permis d'écrire le billet Cast versus As ou que Seb utilise dans son billet Utiliser string.ToLower() c'est mal ! pour tester les perf de ses deux méthodes.

Le principe est simple, vous lui passez en entrée N méthodes C# à tester et en sortie vous récupérez un rapport du style :
 (Seb, je me permet d'utiliser ta capture :))
Sur cet exemple, 2 méthodes ont été chronométrées 5 fois. Chaque colonne représente une méthode.
La moyenne des temps est calculée et un pourcentage exprime la diférence entre la méthode courante et la méthode la plus rapide.

Au niveau code, tout est basé sur une méthode "Test" dont voici la signature :

public delegate void MethodToTest();

/// <summary>
/// Writes on the standard output a performance report of several given methods.
/// <remarks>To be relevant, each report time must be greater than 20ms.</remarks>
/// </summary>
/// <param name="iterCount">Iteration count, a method is executed several time while being timed.
/// Change this argument to increase or decrease this time.</param>
/// <param name="testCount">Report row count.
/// More test are done, more relevant is the final average time.</param>
/// <param name="methods">Methods to test.</param>
public
static void Test(int iterCount, int testCount, params MethodToTest[] methods)
{ ... }
 

  • "iterCount" représente le nombre d'itérations à réaliser durant le test d'une méthode. Dans l'archive ZIP jointe à ce billet, vous verrez que je teste la différence entre un for et un foreach. Etant donné la rapidité de ces instructions et pour pouvoir mesurer un temps pertinent, chaque méthode est exécutée 3000 fois.
  • "testCount" est le nombre de tests qui seront lancés, c'est-à-dire le nombre de lignes que comportera le rapport affiché. Dans la capture d'écran de Seb ci-dessus, testCount a pour valeur 5.
  • "methods" est un tableau de délégués à lancer.

Voici un exemple d'utilisation :

class Program
{
   static int[] coll = new int[100000];

   static void Main(string[] args)
   {
      Test(
         3000,
         10,
         delegate
         {
            for (int l = 0; l < 100000; l++);
         },
         delegate
         {
            foreach (int l in coll);
         });
   }
}

Quelques remarques pour finir :

  • N'oubliez pas que votre config de build influe sur les perfs mesurées. Il arrive qu'une méthode soit plus rapide qu'une autre en Debug et que cela ne soit plus vrai en Release après optimisation du code par le compilateur.
  • Vous noterez dans mon exemple que la collection "coll" utilisée par le foreach est statique. Pourquoi ? Pour que l'instantiation de la collection ne rentre pas en compte dans le calcul de perfs du second délégué.

En espérant que cela vous soit utile :)

Posted: févr. 13 2008, 11:42 par Toutoune_31 | avec 8 comment(s)
Classé sous :
Obtenir le Namespace par défaut d'un projet (dans un Addin Visual Studio 2005)

Bon, vu le temps que j'ai passé à trouver l'infos, je la partage avec vous !
Dans la msdn (http://msdn2.microsoft.com/fr-fr/library/1c02s1da.aspx), on peut trouver l'exemple suivant :

To find the default namespace for your project

  • Test the top-level code elements of the project. Any code element that is a CodeType returns the CodeNamespace element for the project.

    Visual Basic
    Sub FindDefaultNamespace()
       Dim cm As CodeModel
       cm = DTE.Solution.Projects.Item(1).CodeModel
    
       Dim ce As CodeElement
       Dim ct As CodeType = Nothing
       Dim defNameSpace As CodeNamespace
       For Each ce In cm.CodeElements
          If TypeOf ce Is CodeType Then
             ct = CType(ce, CodeType)
             defNameSpace = ct.Namespace
          End If
       Next
    
       If Not IsNothing(defNameSpace) Then
          MsgBox(defNameSpace.Name)
       End If
    End Sub

... Mais cela ne marche pas chez moi. Aucun élément de CodeElements n'est du type "CodeType". Du coup voici la bonne méthode :

(C#)
(string) _applicationObject.SelectedItems.Item(1).Project.Properties.Item("DefaultNamespace").Value

En espérant que cela vous soit aussi utile qu'à moi ;)

Silverlight 2.0

Scott Guthrie, le grand chef Silverlight, vient d'annoncer que la prochaine version sera la 2.0, qu'elle contiendra le toolkit tant attendu et que sa beta verra le jour au premier trimestre 2008 !!!

Pour ceux qui n'auraient pas pu assister au Tour de France Silverlight, Christophe Lauer vient de publier le WebCast de la session de Paris sur son blog. A ne pas rater !

Posted: nov. 30 2007, 09:09 par Toutoune_31 | avec 1 comment(s)
Classé sous : ,
Visual Studio 2008 et Rosario

Visual Studio 2008 est en RTM depuis 10 jours. Il est disponible pour les abonnés MSDN, en version Express ou d'évaluation pour le reste du monde (évaluation Team Suite, Professional).

Du coup les regards se tournent désormais vers Rosario, le futur Visual Studio qui ne verra pas le jour avant 2009-2010.
Rosario proposera son lot de fonctionnalités alléchantes comme le débug avec mémoire (vous pouviez allez à l'instruction suivante, vous pourrez allez à la précédente) ou les log de débug...
Envie de tester la CTP de Novembre de Rosario ?

WebParts & UpdatePanel

Par défaut les WebParts ne fonctionnent pas correctement contenues dans les UpdatePanels des extensions AJAX 1.0.
Voici un très bon post qui explique comment contourner le problème.

Cast versus As

Salut à toi codeur fou,

Après un débat mouvementé sur le cast et quelques tests pour vérifier tout ça, voici de quoi épater tous tes potes !
(Je m'excuse, mes soirées sont parfois longues en ce moment)

Mes tests ont porté sur les différences entre :

MaClasse a = (MaClasse) b;

et...

MaClasse a = b as MaClasse;

Résultat: le cast est plus rapide que le as de 8% en moyenne...

En espérant que cela vous soit utile !

ASP.NET AJAX (ATLAS) v1.0

Voilà ça y est ! La RTM d'ASP.NET AJAX, connue également sous le nom d'ATLAS, est sortie hier et est disponible au téléchargement. Je vous conseille d'aller voir ce que contient le Control Toolkit. Pas mal de contrôles valent le détour.

Pour plus d'info : http://ajax.asp.net/

Généricité contraintes en C#

Comme en Java 5, il est possible d'imposer des contraintes de généricité en C#.

Le type T doit implémenter une interface donnée :

public class MyGenericClass<T> where T:IComparable
{
   ...
}

Le type T doit hériter d'une classe donnée :

public class MyGenericClass<T> where T:MyParentClass
{
   ...
}

Le type T doit être une classe, et le type U une structure :

// cs_where.cs
// compile with: /target:library
using System;

class MyClassy<T, U>
    where T : class
    where U : struct
{
}

Syntaxe (MSDN) : http://msdn2.microsoft.com/en-us/library/6b0scde8.aspx
Contraintes sur les types (MSDN) : http://msdn2.microsoft.com/en-us/library/d5x73970.aspx

Posted: nov. 21 2006, 09:54 par Toutoune_31 | avec 7 comment(s)
Classé sous :
Windows Vista sort aujourd'hui

Ca y est on est le 8 novembre, Microsoft devrait officialiser la RTM de Windows Vista !

L'info vient de blink.nu.

Sorties Microsoft du jour

News MS : http://www.microsoft.com/presspass/press/2006/nov06/11-06MSVisualStudioPR.mspx

 Au passage, je viens de remarquer que Betaplace a été fermée, laissant Connect tout seul.

Obtenir les promotions d'un produit dans Microsoft Commerce Server 2007

Voici un petit article qui n'intéressera sûrement pas le plus grand nombre...
Etant donné le mal que j'ai eu à rassembler ces informations, je les partage avec vous.

Commerce Server 2007 (et ses précédents) ne prévoit pas de fournir les promotions d'un produit avant que celui-ci ne soit ajouté à un caddie. Voici comment obtenir toutes les promos d'un produit donné sans passer par le panier :

1) Le Web.Config :

Ajoutez ou décommentez la section :

<CommerceServer>
  <caches>
    <cache name="Discounts" type="Discounts" refreshInterval="0" retryInterval="30" />
  </caches>
</CommerceServer>

Le cache loader de base est le composant de pipeline CSFLoadDiscounts. Si vous avez besoin de le changer, modifier l'attribut loaderprogid de l'élément <cache /> qui par défaut est positionné à "Commerce.CSFLoadDiscounts".

<cache loaderprogid="MonLoader" ... />

2) Parcourir les promotions d'un produit spécifique (C#) :

// Chargement des promos depuis le cache
//
"Discounts" est le nom du cache dans le Web.config
DiscountItemCollection allDiscounts =
DiscountItemCollection.CreateFromCache("Discounts");

// Création d'un filtre
DiscountCriteriaFilter filter = new DiscountCriteriaFilter();

// Application du filtre sur les promotions
DiscountItemCollection applicableDiscounts =
allDiscounts.ApplyProductFilter(filter, CatalogName, ProductID);

foreach(DiscountItem item in applicableDiscounts)
{
  // Accéder au propriété de la promotion : comme la valeur de la promo 
  // item["offer_type"] == 1 si promo en montant, 2 si promo en pourcentage
  // item["offer_value"] == valeur de la promotion. Attention si remise en pourcentage, cette valeur est comprise entre 0 et 100.
  // etc...

}

Vous trouverez un tableau récapitulatif des propriétés de l'objet DiscountItem dans la documentation du cache loader :
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/CS07Default/html/0bffcd15-24f3-4730-8c67-84a92c7519c6.asp

En espérant que tout ça vous soit autant utile qu'à moi.

Requêtes SQL récursives

Voici une nouvelle fonctionnalité qu'offre Microsoft SQL 2005 et que je viens de découvrir : les requêtes récursives grâce aux  "Common Table Expressions" (CTE).

Ces requêtes permettent de manipuler des hierarchies de données (Parent => Enfants) comme des catégories > sous-catégories > ... > sous-catégories.
La syntaxe est la suivante :

WITH cte_name ( column_name [,...n] )
AS
(

Requête de définition

UNION ALL

Requête récursive

)

Requête utilisant cte_name

La requête de définition reprend les colonnes spécifiées en argument de la CTE et décrit l'élément parent, l'élément de départ de la requête.

La requête récursive permet de définir la manière d'accéder aux enfants. Pour la construire, il suffit de faire référence à la CTE comme s'il sagissait d'une table ou d'une vue. Voici un exemple tiré de la MSDN :

WITH DirectReports (ManagerID, EmployeeID, Title, DeptID, Level)
AS
(
    -- Anchor member definition
    SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID,
           0 AS Level
      FROM HumanResources.Employee AS e
     INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
        ON e.EmployeeID = edh.EmployeeID AND edh.EndDate IS NULL
     WHERE ManagerID IS NULL

    UNION ALL

    -- Recursive member definition
    SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID,
           Level + 1
      FROM HumanResources.Employee AS e
     INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
        ON e.EmployeeID = edh.EmployeeID AND edh.EndDate IS NULL
     INNER JOIN DirectReports AS d
        ON e.ManagerID = d.EmployeeID
)

-- Statement that executes the CTE
SELECT ManagerID, EmployeeID, Title, Level
  FROM DirectReports
 INNER JOIN HumanResources.Department AS dp
    ON DirectReports.DeptID = dp.DepartmentID
 WHERE dp.GroupName = N'Research and Development' OR Level = 0;
GO

Pour plus de détails, voici la référence dans la MSDN :
Source : http://msdn2.microsoft.com/en-us/library/ms186243.aspx

Posted: oct. 16 2006, 11:20 par Toutoune_31 | avec 8 comment(s)
Classé sous :
Remplacement de chaîne dans un fichier

Actuellement je travaille sur des fichiers XML de 8-10 Mo. Je remplace des chaînes de caractères par-ci par-là. Mon souci est simple, comment faire pour remplacer un bout de texte sans perdre trois jours ?

  • Visual Studio prend des ressources astronomiques et un temps fou à cause de toute la mise en page graphique du fichier XML et de sa gestion du retour à l'état précédent... Autrement dit, remplacer une chaîne selon une expression régulière me laisse à chaque fois le temps de faire une petite sieste et occupe jusqu'à 550 Mo de ma RAM, si j'ai le malheur d'avoir 2 de ces fichiers ouverts.
  • Mon fidèle notepad croule sous la tâche avec un simple remplacement de chaîne.

Du coup, j'ai fait une petite appli en C# (Framework 2.0) qui permet de remplacer du texte en ligne de commande selon une chaîne classique de caractères ou une expression régulière. Sur mes fichiers de 8-10Mo, le résultat est quasi instantanné.

StrReplace.exe ExpressionATrouver Remplacement FichierSource [FichierDestination]

Voici le code :

using System;
using System.IO;
using System.Text.RegularExpressions;

namespace StrReplace
{
    public class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.WriteLine("\nStrReplace.exe OldExpr NewExpr FileSrc [FileDest]");
                return;
            }


            string oldExpr     = args[0];       // String or RegEx pattern to find
            string newExpr     = args[1];       // Replacement
            string strFileSrc  = args[2];       // Source filename
            string content     = string.Empty;  // Source file content
            string strFileDest = string.Empty;  // Destination filename if different


            // Reading of the Source
            using(StreamReader FileSrc = new StreamReader(strFileSrc))
            {
                content = FileSrc.ReadToEnd();
                FileSrc.Close();
            }


            Regex ex = new Regex(oldExpr);
            content = ex.Replace(content, newExpr);

           
            // Check of the destination file
            if (args.Length > 3)
                strFileDest = args[3];
            else
                strFileDest = strFileSrc;


            // Creation/replacement of the destination file.
            using (StreamWriter FileDest = new StreamWriter(strFileDest))
            {
                FileDest.Write(content);
                FileDest.Close();
            }
        }
    }
}

En espérant que ça vous serve. Si vous avez des commentaires, n'hésitez pas.

Posted: oct. 09 2006, 01:55 par Toutoune_31 | avec no comments
Classé sous :
Google Code Search

Je viens de découvrir le Google Code Search, ça a l'air assez puissant et bien foutu. Le moteur de recherche permet de trouver des exemples de codes dans des fichiers sources publiés sur le net.

http://www.google.com/codesearch

Posted: oct. 05 2006, 11:12 par Toutoune_31 | avec no comments
Classé sous :
Plus de Messages Page suivante »