Reputation: 8055
I know the fact that C# doesn't support properties with arguments except the default properties. But I think still it's nice to have such feature in some situations. As an example, an application might have settings which are specific to the language currently used. So such settings property may look like this.
settings.IsContentDownloaded["en-US"] = true;
Event thought this doesn't support by default, we can come up with a workaround to simulate this with other great feature available in the language. But the problem is what is the best workaround which provide a generalized approach to this problem.
I have my own workaround for this and I have shared it as an answer. But I'm looking for a better approach or any improvement to my approach.
Upvotes: 0
Views: 109
Reputation: 11273
Its an interesting question, here is a method I came up with:
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;
}
}
Here LocalizableSetting
stores localized values in an internal dictionary, which is really nothing special, however I added a feature that allows it to be used like normal properties as well, the implicit conversion operators.
This does take some tricks to use though, in order to properly use it in a class, you cannot use auto-properties, since you have to merge the two on a set, not overwrite it, so here is an example of how to use it in a class:
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;
}
}
}
Notice that in the set
method, it iterates through the values and either overwrites the current one or adds a new one (with the help of the indexer).
So, this allows you to do something like this:
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;
}
}
Where multipleSetting
will be the multiple of the current culture values for that property due to the implicit conversion from LocalizableSetting<int>
to int
. The c.IntSetting = 10
causes an implicit conversion from the source type (int
) to a LocalizableSetting<int>
and then assigns it to the property, this is why a merge is needed instead of an overwrite.
There are a couple (big) holes that I left here, namely that the property should return some default value if the value for that culture is not found (currently it will throw an exception). But it shows one method of solving this issue.
Upvotes: 1
Reputation: 514
create a dictionary where the keys are your strings such as "en-US" and the values are a bool:
Dictionary<string, bool> aaa = new Dictionary<string, bool>();
aaa.Add("en-US", true);
if(aaa["en-US"].Equals(true))
{
}
Upvotes: 1
Reputation: 8055
I have used dictionary named _settingsRepositoty
to store settings, but it might be anything which use to store setting based on the application type.
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];
}
}
}
Upvotes: 0