【问题标题】:Using the typical get set properties in C#... with parameters在 C# 中使用典型的 get set 属性...带参数
【发布时间】:2010-09-19 04:31:51
【问题描述】:

我想在 C# 中做同样的事情。有没有像我在这个 VB.NET 示例中使用参数“Key”一样在 C# 中使用带有参数的属性?

Private Shared m_Dictionary As IDictionary(Of String, Object) = New Dictionary(Of String, Object)
Public Shared Property DictionaryElement(ByVal Key As String) As Object
    Get
        If m_Dictionary.ContainsKey(Key) Then
            Return m_Dictionary(Key)
        Else
            Return [String].Empty
        End If
    End Get
    Set(ByVal value As Object)
        If m_Dictionary.ContainsKey(Key) Then
            m_Dictionary(Key) = value
        Else
            m_Dictionary.Add(Key, value)
        End If

    End Set
End Property

谢谢

【问题讨论】:

    标签: c# vb.net properties


    【解决方案1】:

    在 C# 中是否可以使用带参数的属性

    没有。您只能在 C# 中为 default 属性提供参数,以对索引访问进行建模(如在字典中):

    public T this[string key] {
        get { return m_Dictionary[key]; }
        set { m_Dictionary[key] = value; }
    }
    

    其他属性不能有参数。改用函数。顺便说一句,建议在 VB 中执行相同的操作,以便其他 .NET 语言(C# ...)可以使用您的代码。

    顺便说一句,您的代码过于复杂。四件事:

    • 您不需要转义String 标识符。直接使用关键字。
    • 为什么不使用""
    • 使用TryGetValue,它更快。您查询字典两次。
    • 您的 setter 不必测试该值是否已经存在。

    Public Shared Property DictionaryElement(ByVal Key As String) As Object
        Get
            Dim ret As String
            If m_Dictionary.TryGetValue(Key, ret) Then Return ret
            Return "" ' Same as String.Empty! '
        End Get
        Set(ByVal value As Object)
            m_Dictionary(Key) = value
        End Set
    End Property
    

    【讨论】:

    • 很好的回答人。不知道您为什么建议使用 "" 而不是 String.Empty,但……原来的对我来说似乎更明确。
    • @Stimul8d:我不关注。 "" 怎么不明确?我在两者之间看到的唯一区别(恕我直言,程序员应该看到)是String.Empty 长六倍,因此它需要六倍的空间和大约六倍的时间阅读所以它使代码差六倍。作为比较,这就好像我们会使用Int32.Zero 而不是0
    【解决方案2】:

    您的代码示例给我的印象是一个非常奇怪的设计和对属性用途的滥用。为什么不只是一个实例方法AddOrUpdateKey

    Public Sub AddOrUpdateKey(ByVal Key As String, ByVal Value as Object)
        If m_Dictionary.ContainsKey(Key) Then
            m_Dictionary(Key) = Value
        Else
            m_Dictionary.Add(Key, Value)
        End If
    End Sub
    

    如果密钥不存在,您的属性也会返回 String.Empty,但声称返回 ObjectString

    【讨论】:

    • 嗨 Sören,使用方法不允许我以这种方式使用代码:Example.DictionaryElement["OneKey"] = "Hello world"; Console.WriteLine(Example.DictionaryElement["OneKey"]);非常感谢
    【解决方案3】:

    在 C# 中执行此操作的“正确”方法是专门创建子类来访问集合。它应该要么持有集合本身,要么与父类有内部链接。

    【讨论】:

      【解决方案4】:

      这是给您的示例(根据 Grauenwolf 的建议进行了更改):

      using System;
      using System.Collections.Generic;
      
      public class Test
      {
          public FakeIndexedPropertyInCSharp DictionaryElement { get; set; }
      
          public Test()
          {
              DictionaryElement = new FakeIndexedPropertyInCSharp();
          }
      
          public class FakeIndexedPropertyInCSharp
          {
              private Dictionary<string, object> m_Dictionary = new Dictionary<string, object>();
      
              public object this[string index]
              {
                  get 
                  {
                      object result;
                      return m_Dictionary.TryGetValue(index, out result) ? result : null;
                  }
                  set 
                  {
                      m_Dictionary[index] = value; 
                  }
              }
          }
      
      
      }
      
      class Program
      {
          static void Main(string[] args)
          {
              Test t = new Test();
              t.DictionaryElement["hello"] = "world";
              Console.WriteLine(t.DictionaryElement["hello"]);
          }
      }
      

      【讨论】:

        【解决方案5】:

        感谢康拉德、艾伦、格劳恩沃尔夫,

        总之,我不能完全像在 VB.NET 中那样使用 C# 属性... :_( 无论如何,你的回答对我来说非常有用,我可能会把这个想法带到我的C# 代码。

        除了属性问题的答案外,还有其他优点。例如,

        • 使用 TryGetValue,它更快。你查询字典两次。
        • 您的 setter 不必测试该值是否已经存在。

        也感谢 Sören,使用一种方法并不适合我最初的目标,但非常感谢。

        【讨论】:

          【解决方案6】:

          针对您的问题的更通用、更安全和可重用的解决方案可能是实现一个通用的“参数化”属性类,如下所示:

              // Generic, parameterized (indexed) "property" template
              public class Property<T>
              {
                  // The internal property value
                  private T PropVal = default(T);
          
                  // The indexed property get/set accessor 
                  //  (Property<T>[index] = newvalue; value = Property<T>[index];)
                  public T this[object key]
                  {
                      get { return PropVal; }     // Get the value
                      set { PropVal = value; }    // Set the value
                  }
              }
          

          然后,您可以在公共类中实现任意数量的属性,以便客户端可以使用索引、描述符、安全密钥或其他任何内容设置/获取属性,如下所示:

              public class ParameterizedProperties
              {
                  // Parameterized properties
                  private Property<int> m_IntProp = new Property<int>();
                  private Property<string> m_StringProp = new Property<string>();
          
                  // Parameterized int property accessor for client access
                  //  (ex: ParameterizedProperties.PublicIntProp[index])
                  public Property<int> PublicIntProp
                  {
                      get { return m_IntProp; }
                  }
          
                  // Parameterized string property accessor
                  //  (ex: ParameterizedProperties.PublicStringProp[index])
                  public Property<string> PublicStringProp
                  {
                      get { return m_StringProp; }
                  }
              }
          

          最后,客户端代码将访问您的公共类的“参数化”属性,如下所示:

                  ParameterizedProperties parmProperties = new ParameterizedProperties();
                  parmProperties.PublicIntProp[1] = 100;
                  parmProperties.PublicStringProp[1] = "whatever";
                  int ival = parmProperties.PublicIntProp[1];
                  string strVal = parmProperties.PublicStringProp[1];
          

          当然,这看起来很奇怪,但它确实可以解决问题。此外,从客户端代码的角度来看,它一点也不奇怪——它简单直观,就像真正的属性一样。它不会破坏任何 C# 规则,也不会与其他 .NET 托管语言不兼容。从类实现者的角度来看,创建一个可重用、通用、“参数化”的属性模板类可以让组件编码变得轻而易举,如下所示。

          注意:您始终可以覆盖通用属性类以提供自定义处理,例如索引查找、安全控制的属性访问或您想要的任何东西。

          干杯!

          马克·琼斯

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-02-23
            • 2016-08-07
            • 1970-01-01
            • 2012-04-05
            • 1970-01-01
            • 2019-04-05
            • 2013-10-24
            • 2012-04-10
            相关资源
            最近更新 更多