9

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

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

谢谢

4

6 回答 6

14

无论如何在 C# 中使用带参数的属性

不可以。您只能在 C# 中提供带有参数的默认属性,以对索引访问进行建模(如在字典中):

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
于 2008-10-25T15:05:37.520 回答
4

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

于 2008-10-25T17:35:45.437 回答
4

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

    // 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 托管语言不兼容。从类实现者的角度来看,创建一个可重用、通用、“参数化”的属性模板类使得组件编码变得相对容易,如下所示。

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

干杯!

马克琼斯

于 2011-06-11T00:55:36.237 回答
3

这是给您的示例(根据 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"]);
    }
}
于 2008-10-25T19:13:16.503 回答
0

您的代码示例让我觉得这是一个非常奇怪的设计,并且滥用了预期的属性。为什么不只是一个实例方法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如果键不存在,您的属性也会返回,但声称返回 aObject或 a String

于 2008-10-25T15:11:33.417 回答
0

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

总之,我不能以与在 VB.NET 中完全相同的方式使用 C# 属性... :_( 无论如何,您的答案对我非常有用,我可能会将这些想法带到我的 C# 代码中。

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

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

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

于 2008-10-26T15:52:18.687 回答