Vous trouverez dans le hors série .net de Programmez un article "Plongée au coeur de .Net 3.5" co-écrit avec Michel Perfetti.
Bonne lecture ![]()
Vous devez être identifié pour poster un commentaire.
L'info est énorme !!!
VS 2008 est dispo dès à présent. Il faut juste avoir un compte msdn pour cela.
Bon téléchargement ![]()
Vous devez être identifié pour poster un commentaire.
Imaginons le code suivant :
int i = 0;
#if DEBUG
i ++;
#else
i--;
#endif
Si je renomme i en j et que je laisse VS le renommer pour moi, j'obtiens le code suivant :
int j = 0;
#if DEBUG
j ++;
#else
i--;
#endif
Je comprends bien la difficulté évoquée par Michael Taylor sur le forum msdn mais je trouve que c'est regrettable.
Vous devez être identifié pour poster un commentaire.
, Matthieu MEZIL Les inscriptions pour le MIX 2008 sont ouvertes.
Pour rappel, le MIX, c'est L'évènement web MS annuel. Comme chaque année, il se fera à Las Vegas et sera ensuite relayé dans le monde entier (au cirque d'hiver de Paris l'année dernière par ex). Cette année, il aura lieu du 5 au 7 mars 2008 au Resort Hotel Casino, Las Vegas, Nevada.
Vous devez être identifié pour poster un commentaire.
Les paramètres optional ne peuvent pas être de type structure. Par conséquent, les nullables ne sont pas autorisés ![]()
Vous devez être identifié pour poster un commentaire.
Dans l'excellent article de Adrian "Spotty" Bowles paru dans le msdn mag sur les extension methods en VB, l'auteur nous explique que ce code :
Imports System.Runtime.CompilerServices
Module Module1
Sub Main()
Dim s As Integer = 1234
Console.WriteLine(s.Foo) '<- This will work
Dim T As Object
T = 1234
Console.WriteLine(T.Foo) '<- This will fail
End Sub
End Module
Module Extensions01
<Extension()> _
Function Foo(ByVal b As Object) As String
Return "Bar01"
End Function
End Module
génère une exception à la compilation et c'est vrai !
Mais pas en C#.
Le code suivant marche en effet très bien :
class Program
{
static void Main(string[] args)
{
object o;
o = 10;
Console.WriteLine(o.Foo());
Console.ReadLine();
}
}
static class Ext
{
public static string Foo(this object o)
{
return "test";
}
}
Vous devez être identifié pour poster un commentaire.
C'est officiel, VS 2008 sortira fin novembre. Que du bonheur en perspective ![]()
Vous devez être identifié pour poster un commentaire.
Si vous utilisez la Beta 2, vous avez sûrement eu le même problème que moi : la version expire au 1er novembre ![]()
Il faut retélécharger les images pour ne plus avoir de limitation.
Vous devez être identifié pour poster un commentaire.
Le défaut de LINQ c'est qu'il va devenir beaucoup plus facile de faire du code moins performant.
Prenons un exemple :
public class Client
{
private List<Facture> _factures;
public string Nom { get; set; }
public string Prenom { get; set; }
public List<Facture> Factures
{
get
{
if (_factures == null)
_factures = new List<Facture>();
return _factures;
}
}
}
public class Facture
{
private Client _client;
public Client Client
{
get { return _client; }
set
{
if (_client != null)
_client.Factures.Remove(this);
_client = value;
_client.Factures.Add(this);
}
}
public decimal Prix { get; set; }
}
Imaginons que l'on veuille récupérer les clients ayant dépensé au moins 50 euros en les triant par ordre décroissant de dépense, puis alphabétiquement.
Le code en C# 2.0 pourrait être le suivant :
List<Client> copyClients = new List<Client>();
copyClients.AddRange(clients);
copyClients.Sort(delegate(Client x, Client y)
{
decimal xFacturesSomme = 0, yFacturesSomme = 0;
foreach (Facture facture in x.Factures)
xFacturesSomme += facture.Prix;
foreach (Facture facture in y.Factures)
yFacturesSomme += facture.Prix;
int compareFactureSomme = xFacturesSomme.CompareTo(yFacturesSomme);
if (compareFactureSomme != 0)
return -compareFactureSomme;
int compareNom = x.Nom.CompareTo(y.Nom);
if (compareNom != 0)
return compareNom;
return x.Prenom.CompareTo(y.Prenom);
});
foreach (Client c in copyClients)
{
decimal facturesSomme = 0;
foreach (Facture facture in c.Factures)
facturesSomme += facture.Prix;
if (facturesSomme > 50)
Console.WriteLine("{0} {1} a dépensé {2} euros", c.Nom, c.Prenom, facturesSomme);
}
Avec LINQ, ce code peut être grandement simplifié. Mais attention, on pourrait écrire ceci :
foreach (var statClient in from c in
(from client in clients
select new
{
client.Nom,
client.Prenom,
TotalDepense = (from f in client.Factures
select f.Prix).Sum()
})
where c.TotalDepense > 50
orderby c.TotalDepense descending, c.Nom, c.Prenom
select c)
Console.WriteLine("{0} {1} a dépensé {2} euros", statClient.Nom, statClient.Prenom, statClient.TotalDepense);
Cependant, analysons de plus près ce code :
Pour calculer la somme totale dépensée par le client, nous parcourons toutes les factures pour récupérer un IEnumerable sur le prix de celles-ci, puis nous reparcourons cet IEnumerable pour faire la somme.
L'idée serait donc de regrouper ces deux boucles en une seule. Pour cela, utilisons une lambda expression et une autre signature de la méthode Sum :
foreach (var statClient in from c in
(from client in clients
select new
{
client.Nom,
client.Prenom,
TotalDepense = client.Factures.Sum(f => f.Prix)
})
where c.TotalDepense > 50
orderby c.TotalDepense descending, c.Nom, c.Prenom
select c)
Console.WriteLine("{0} {1} a dépensé {2} euros", statClient.Nom, statClient.Prenom, statClient.TotalDepense);
L'autre problème que l'on peut identifier, c'est le fait que nous parcourons une première boucle sur les clients pour récupérer un IEnumerable de type anonyme avec le nom, le prénom et la somme dépensée et qu'ensuite, nous reparcourons cet IEnumerable pour les trier. Effectivement, pour pouvoir trier par la somme dépensée, il faut au préalable l'avoir calculée.
Là encore, une meilleure utilisation de LINQ pourrait nous permettre d'optimiser cela :
foreach (var statClient in from c in clients
let totalDepense = c.Factures.Sum(f => f.Prix)
where totalDepense > 50
orderby totalDepense descending, c.Nom, c.Prenom
select new
{
c.Nom,
c.Prenom,
TotalDepense = totalDepense
})
Console.WriteLine("{0} {1} a dépensé {2} euros", statClient.Nom, statClient.Prenom, statClient.TotalDepense);
Via ce post, je cherche à démontrer deux choses :
la requête LINQ est beaucoup plus simple et claire que le code C# 2.0.
une mauvaise connaissance de LINQ peut engendrer des pertes de performances importantes.
En revanche, avec LINQ To SQL, même si je ne vous conseille bien entendu pas d'écrire de "mauvaises" requêtes, la requête SQL générée est optimisée. Dans les trois cas précédents, la requête sera la suivante :
SELECT [t2].[Nom], [t2].[Prenom], [t2].[value] AS [TotalDepense]
FROM (
SELECT [t0].[Nom], [t0].[Prenom], (
SELECT SUM([t1].[Prix])
FROM [dbo].[Facture] AS [t1]
WHERE [t1].[Client] = [t0].[Id]
) AS [value]
FROM [dbo].[Client] AS [t0]
) AS [t2]
WHERE [t2].[value] > @p0
ORDER BY [t2].[value] DESC, [t2].[Nom], [t2].[Prenom]
Le risque lié à une mauvaise connaissance de LINQ peut cependant être fortement réduit avec une formation (http://www.winwise.fr/formation/Presentation-de-LINQ-W095.aspx par exemple).
Vous devez être identifié pour poster un commentaire.
, Matthieu MEZIL J'avais blogué sur le fait que le Update de LINQ To SQL se faisait sur toutes les colonnes, y compris celles qui n'ont pas changés, ce qui peut poser des problèmes si vous avez des triggers sur le update de la table SQL.
En réalité, j'avais bloggué un peu vite. En effet, de même qu'il est possible de ne charger des colonnes qu'au moment de l'utilisation de la propriété associée (Delay Loaded = true) avec System.Data.Linq.Link<T>, il est possible de ne pas inclure une colonne à l'update si celle-ci n'a pas été modifiée avec l'attribut UpdateCheck=UpdateCheck.WhenChanged.
Vous pouvez retrouver Delay Loaded et Update Check dans la property grid du designer LINQ To SQL.
Vous devez être identifié pour poster un commentaire.
J'avais précédemment blogué sur le fait qu'une méthode partielle ne peut pas être public ni même protected et ne peut par conséquent pas être virtuelle.
J'ai enfin compris pourquoi :
Quand la méthode partielle n'est pas redéfinie, le compilateur supprime tout simplement les appels à celle-ci. Ainsi le code suivant :
public Client()
{
OnCreated();
this._Factures = new EntitySet<Facture>(new Action<Facture>(this.attach_Factures), new Action<Facture>(this.detach_Factures));
}
devient avec Reflector (donc à partir du code compilé) :
public Client()
{
this._Factures = new EntitySet<Facture>(new Action<Facture>(this.attach_Factures), new Action<Facture>(this.detach_Factures));
}
La seule solution que je vois pour ne pas avoir les contraintes énoncées au début de ce post aurait été de prendre un autre choix : plutôt que de retirer les appels à la méthode partielle non redéfinie, le compilateur aurait pu générer cette méthode (mais en ne faisant rien). Cependant, je doute fort que les équipes de MS n'y ait pas pensé. Je pense plutôt qu'il me manque des éléments permettant de comprendre les raisons de ce choix. Si quelqu'un a plus d'info, n'hésitez surtout pas à me laisser un commentaire.
Pour les mêmes raisons, l'appel à la méthode partielle OnValidate ne peut se faire que par Reflexion.
Vous devez être identifié pour poster un commentaire.
Je viens d'avoir une mauvaise surprise sur un truc tout bête :
J'ai une Form avec la propriété StartPosition = CenterParent.
Quand je l'ouvre en modal (ShowDialog), pas de soucis, elle est bien au milieu de la form appelante mais pas avec un simple Show
(bien entendu, je lui passe le owner dans les deux cas. Du coup je dois le calculer manuellement à partir du Owner.
J'en conviens, ce n'est pas très compliqué, mais j'aimerais comprendre. Si quelqu'un a déjà rencontré ce problème et trouvé une solution mieux que le recalcule, n'hésitez surtout pas à me laisser un commentaire.
Vous devez être identifié pour poster un commentaire.
| Lun | Mar | Mer | Jeu | Ven | Sam | Dim |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |