c#属性带参数的解决方案

本文关键字:解决方案 参数 属性 | 更新日期: 2023-09-27 18:19:03

我知道c#除了默认属性外不支持带参数的属性。但我认为在某些情况下有这样的功能还是不错的。例如,应用程序可能具有特定于当前使用的语言的设置。因此,这样的设置属性可能看起来像这样。

settings.IsContentDownloaded["en-US"] = true;
虽然默认情况下不支持

Event,但我们可以想出一个解决方案,用该语言中可用的其他重要功能来模拟它。但问题是什么是最好的解决方法,提供一个通用的方法来解决这个问题。

我有我自己的解决方法,我已经分享了它作为答案。但是我正在寻找一个更好的方法或任何改进我的方法。

c#属性带参数的解决方案

创建一个字典,其中键是您的字符串,如"en-US",值是bool值:

Dictionary<string, bool> aaa = new Dictionary<string, bool>();
aaa.Add("en-US", true);
if(aaa["en-US"].Equals(true))
{
}

这是一个有趣的问题,这是我想到的一个方法:

public class LocalizableSetting<T> : IEnumerable<KeyValuePair<string, T>>
{
    private Dictionary<string, T> _values;
    public T this[string cultureName]
    {
        get { return _values[cultureName]; }
        set
        {
            _values[cultureName] = value;
        }
    }
    public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
    {
        return _values.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return _values.GetEnumerator();
    }
    public static implicit operator T(LocalizableSetting<T> value)
    {
        return value[CultureInfo.CurrentCulture.Name];
    }
    public static implicit operator LocalizableSetting<T>(T value)
    {
        var setting = new LocalizableSetting<T>();
        setting[CultureInfo.CurrentCulture.Name] = value;
        return setting;
    }
}

这里LocalizableSetting在内部字典中存储本地化的值,这实际上没有什么特别的,但是我添加了一个功能,允许它像普通属性一样使用,隐式转换操作符。

这确实需要一些技巧来使用,但是为了在类中正确使用它,不能使用auto-properties,因为你必须在一个集合上合并两者,而不是覆盖它,所以这里有一个如何在类中使用它的示例:

public class SomeLocalizableClass
{
    //Explicitly declare the backing field for the property!
    private LocalizableSetting<int> _intSetting = new LocalizableSetting<int>();
    public LocalizableSetting<int> IntSetting
    {
        get { return _intSetting; }
        set
        {
            //Merge, don't overwrite
            foreach (var kvp in value)
                _intSetting[kvp.Key] = kvp.Value;
        }
    }
}

请注意,在set方法中,它遍历值并覆盖当前值或添加新值(在索引器的帮助下)。

所以,这允许你做这样的事情:

public class SomeConsumerClass
{
    public void SomeMethod()
    {
        SomeLocalizableClass c = new SomeLocalizableClass();
        c.IntSetting["fr-FR"] = 4;      //Sets the french setting
        c.IntSetting = 10;              //Sets the current culture setting
        int multipleSetting = c.IntSetting * c.IntSetting;
    }
}

其中multipleSetting将是该属性的当前区域性值的倍数,因为从LocalizableSetting<int>隐式转换为intc.IntSetting = 10导致从源类型(int)到LocalizableSetting<int>的隐式转换,然后将其分配给属性,这就是需要合并而不是覆盖的原因。

我在这里留下了几个(大)漏洞,即如果没有找到该区域性的值,该属性应该返回一些默认值(目前它将抛出异常)。但是它展示了一种解决这个问题的方法。

我使用名为_settingsRepositoty的字典来存储设置,但它可以是任何用于存储基于应用程序类型的设置的东西。

public class Settings
{
    private Dictionary<string, object> _settingsRepository = new Dictionary<string, object>();
    private LanguageSpecificPropertyFactory _factory;
    public Settings()
    {
        _factory = new LanguageSpecificPropertyFactory(this);
    }
    public LanguageSpecificProperty<bool> IsContentDownloaded
    {
        get
        {
            return _factory.GetLanguageProperty("IsContentDownloaded", false);
        }
    }
    private void Set<T>(string propertyName, string lang, T val)
    {
        string fullPropertyName = string.Format("{0}_{1}", propertyName, lang);
        _settingsRepository[fullPropertyName] = val;
    }
    private T Get<T>(string propertyName, string lang, T defaultValue)
    {
        string fullPropertyName = string.Format("{0}_{1}", propertyName, lang);
        if (!_settingsRepository.ContainsKey(fullPropertyName))
        {
            _settingsRepository[fullPropertyName] = defaultValue;
        }
        return (T)_settingsRepository[fullPropertyName];
    }
    public class LanguageSpecificProperty<T>
    {
        private string _properyName;
        private T _defaultValue;
        private Settings _settings;
        internal LanguageSpecificProperty(Settings settings, string propertyName, T defaultValue)
        {
            _properyName = propertyName;
            _defaultValue = defaultValue;
        }
        public T this[string lang]
        {
            get
            {
                return _settings.Get<T>(_properyName, lang, _defaultValue);
            }
            set
            {
                _settings.Set<T>(_properyName, lang, value);
            }
        }
    }
    public class LanguageSpecificPropertyFactory
    {
        private Dictionary<string, object> _properties = new Dictionary<string, object>();
        private Settings _settings;
        public LanguageSpecificPropertyFactory(Settings settings)
        {
            _settings = settings;
        }
        internal LanguageSpecificProperty<T> GetLanguageProperty<T>(string propertyName, T defaultValue)
        {
            if (!_properties.ContainsKey(propertyName))
            {
                _properties.Add(propertyName, new LanguageSpecificProperty<T>(_settings, propertyName, defaultValue));
            }
            return (LanguageSpecificProperty<T>)_properties[propertyName];
        }
    }
}