2009-07-06 57 views
2

我有这样一个类:C#索引器属性问题

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]; 
     } 
    } 
} 

现在,如果此伊...

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

...并没有钥匙13,我会得到一个错误是这样的:

The given key was not present in the dictionary.

我想有一个能以同样的方式与上述被访问的属性,BU如果没有密钥,t将返回一个默认对象。

我试图创建一个索引属性是这样的...

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

......但看起来这不是一个C#2008语言功能。

如何以同样的方式访问属性,但如果密钥不存在则获取默认对象?

回答

5

您必须使用具有所需行为的索引器定义您自己的基于IDictionary的类,并在属性获取器中返回该实例,而不是股票Dictionary类。

2

Indexers in C#只能与this关键字一起使用。

我怀疑你想是这样的:

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

,你可以定义直接在SomeClass,这样就可以访问privelege项目,如:

SomeClass foo; 
var bar = foo[100]; 

或在定义该索引自定义类实现从IDictionary<TKey, TValue>(并在内部包含Dictionary<TKey, TValue实际存储数据)。然后,您可以像这样使用它:

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

这是您似乎建议的语法,它可能是最合适的,但它需要更多的努力。

+0

使用异常处理控制流是一个坏理念。它使得你的程序很难调试(因为通常你想要在第一次机会异常跟踪的时候进行调试,而且大量无关的异常会使它们变得更难),这使得它们变得很慢,并且它违背了例外情况下的设计事实是例外。最好首先检查键是否存在,而不是尝试它并在没有时捕获异常。 – 2009-07-06 18:27:26

+0

@Eric:很公平 - 我在发布回复之前就已经意识到这一点;然而,问题还涉及到问题的属性/索引方面。您应该在原始问题上发表您的评论。 – Noldorin 2009-07-06 18:31:38

-1

你应该使用这个语法来检索值:

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

我需要这种使用的IDictionary的很多,所以我做了一些扩展方法:

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; 
} 

现在你可以这样写:

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

这不是有效的C#!索引器只能与`this`关键字一起使用。 – Noldorin 2009-07-06 17:38:28

6

C#不支持命名索引器,因为你已经发现了。

您是否考虑过使用常规方法而不是索引器属性?并非每个编程问题都需要使用花哨的语法来解决。是的,您可以使用聚合字典创建自己的IDictionary实现,并更改属性访问行为 - 但对于只提取值或返回默认值的东西,这真的是必需的吗?

我想这个方法添加到您的类:

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

或者更好,避免异常处理的流量控制机制:

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