2009-07-06 12 views
2

J'ai une classe comme ceci:C# Indexer propriété Question

public class SomeClass 
{ 
    private const string sessionKey = "__Privileges"; 
    public Dictionary<int, Privilege> Privileges 
    { 
     get 
     { 
      if (Session[sessionKey] == null) 
      { 
       Session[sessionKey] = new Dictionary<int, Privilege>(); 
      } 

      return (Dictionary<int, Privilege>)Session[sessionKey]; 
     } 
    } 
} 

Maintenant, si ce Ido ...

var someClass = new SomeClass(); 
var p = someClass.Privileges[13]; 

... et il n'y a pas 13 clé, je vais obtenir un erreur comme ceci:

The given key was not present in the dictionary.

Je voudrais avoir une propriété qui est accessible de la même manière que ci-dessus, bu t retournera un objet par défaut en cas d'absence de la clé.

J'ai essayé de créer une propriété indexeur comme ça ...

public Privilege Privileges[int key] 
    { 
     get 
     { 
      try { return _privileges[key]; } 
      catch { return new Privilege(); } 
     } 
    } 

... mais il semble que ce n'est pas une fonctionnalité de langage C# 2008.

Comment puis-je accéder à la propriété de la même manière, mais obtenir l'objet par défaut si la clé n'est pas présente?

Répondre

5

Vous devrez définir votre propre classe basée sur IDictionary avec un indexeur qui a le comportement souhaité, et renvoyer une instance de celui-ci, plutôt que la classe Dictionary, dans votre getter de propriété.

2

Indexers en C# ne peut être utilisé qu'avec le mot-clé this.

Je suppose que vous voulez quelque chose comme ceci:

public Privilege this[int key] 
{ 
    get 
    { 
     try { return _privileges[key]; } 
     catch { return default(Privelege); } 
    } 
} 

que vous pouvez définir soit directement dans SomeClass afin que vous puissiez accéder à un élément privelege comme:

SomeClass foo; 
var bar = foo[100]; 

ou définir cette indexeur dans un classe personnalisée qui implémente à partir de IDictionary<TKey, TValue> (et contient un Dictionary<TKey, TValue en interne pour réellement stocker les données). Vous pouvez alors l'utiliser comme:

SomeClass foo; 
var bar = foo.Priveleges[100]; 

Quelle est la syntaxe que vous semblez proposer, et qui peut être manière la plus adéquate, mais il faut un peu plus d'efforts.

+0

En utilisant la gestion des exceptions comme flux de contrôle est une mauvaise idée. Cela rend vos programmes difficiles à déboguer (parce que souvent vous voulez déboguer avec le suivi des exceptions de première chance, et beaucoup d'exceptions externes le rendent plus difficile), cela les ralentit, et cela va à l'encontre du fait que les exceptions sont supposées être exceptionnel. Il est préférable de vérifier d'abord si la clé existe, plutôt que de l'essayer et d'attraper l'exception lorsque ce n'est pas le cas. –

+0

@Eric: Très bon point - J'en étais conscient avant de poster la réponse; cependant, la question se rapportait d'ailleurs à l'aspect propriété/indexeur de la question. Vous devriez probablement poster votre commentaire sur la question originale. – Noldorin

-1

Vous devez utiliser cette syntaxe pour récupérer la valeur:

public Privilege this[int key] 
{ 
    get 
    { 
     var value = (Privilege)null; 
     if(!_privileges.TryGetValue(key, out value)) 
      value = new Privilege(); 
     return value; 
    } 
} 

J'ai un besoin pour ce genre d'utilisation de IDictionary beaucoup, donc je fait quelques méthodes d'extension:

public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key) 
{ 
    TValue v = default(TValue); 
    d.TryGetValue(key, out v); 
    return v; 
} 
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> value) 
{ 
    TValue v = d.Get(key); 
    if (v == null) 
    { 
     v = value(); 
     d.Add(key, v); 
    } 
    return v; 
} 

maintenant vous pourriez écrire:

public Privilege this[int key] 
{ 
    get 
    { 
     return _privileges.Get(key,() => new Privilege()); 
    } 
} 
+1

Ce n'est pas valide C#! Les indexeurs ne peuvent être utilisés qu'avec le mot clé 'this'. – Noldorin

6

C# ne supporte pas les indexeurs nommés, comme vous l'avez découvert.

Avez-vous envisagé d'utiliser une méthode régulière au lieu d'une propriété indexeur? Tous les problèmes de programmation ne nécessitent pas l'utilisation de la syntaxe sophistiquée. Oui, vous pouvez créer votre propre implémentation IDictionary avec un dictionnaire agrégé et modifier le comportement d'accès à la propriété - mais est-ce vraiment nécessaire pour quelque chose qui récupère simplement une valeur ou retourne une valeur par défaut?

Je voudrais ajouter une méthode comme celui-ci à votre classe:

protected Privilege GetPrivilege(int key) 
{ 
    try { return _privileges[key]; } 
    catch { return new Privilege(); } 
} 

ou mieux encore, d'éviter la gestion des exceptions comme un mécanisme de contrôle de flux:

protected Privilege GetPrivilge(int key) 
{ 
    Privilege priv; 
    if(_privileges.TryGetValue(key, out priv)) 
     return priv; 
    else 
     return new Privilege(); 
} 
+0

Bon conseil. J'ai pris vos conseils pour résoudre mon problème. J'ai déjà utilisé la gestion des exceptions pour le contrôle de flux, mais je n'ai pas pensé que c'était une mauvaise chose, jusqu'à maintenant. Merci. –