I'm basically reading a config file
[Section] Key=value
Where the value
can be either a string, an integer, a double, or a boolean value.
While working in this context, I have a class that looks like this...
public class Setting
{
public string Section {get; set;}
public string Key {get; set;}
public <string, int, double, or bool> Value {get; set;}
public Setting(string section, string key, <string, int, double, or bool> value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
//if Value is an int, call third-party code to write an integer to the config file.
//if Value is a string, call third-party code to write a string to the config file.
//...
}
}
In this situation, what is the accepted way to handle the Value
property of this class?
In addition, I'd like to be able to store a bunch of these objects in an Array, List, or other types of collections.
UPDATE:
I'm not reading/writing to the configuration file directly, that part of the code is not controlled by me. Basically, I need to call different functions in the third-party code, based on the type of Value
UPDATE:
One thought was to use generics, and have a class like this...
public class Setting<T>
{
public string Section { get; set; }
public string Key { get; set; }
public T Value { get; set; }
public Setting(string section, string key, T value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(typeof(T)))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
default:
break;
}
}
}
But then I'd only be able to store a single type of setting in a List.
System.Collections.Generic.List<Setting<string>> settings = new List<Setting<string>>();
So I'd have to have a list for each type of setting.
UPDATE:
Another option might be to use and interface, and classes for each type of setting that implement the interface...
interface ISetting
{
string Section { get; set; }
string Key { get; set; }
void Write();
}
public class StringSetting : ISetting
{
public string Section { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public StringSetting(string section, string key, string value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
//Call third-party code to write the setting.
}
}
But that seems like a lot of duplicate code, so making changes in the future might be error prone.
UPDATE:
Another option, is to make Value
a dynamic type.
public class DynamicSetting
{
public string Section { get; set; }
public string Key { get; set; }
public dynamic Value { get; set; }
public DynamicSetting(string section, string key, dynamic value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
default:
break;
}
}
}
Then I can create a bunch of DynamicSetting objects, and store them in a collection like I want.
DynamicSetting IntSetting = new DynamicSetting("Section", "Key", 1);
DynamicSetting StringSetting = new DynamicSetting("Section", "Key", "1");
DynamicSetting DoubleSetting = new DynamicSetting("Section", "Key", 1.0);
System.Collections.Generic.List<DynamicSetting> settings = new List<DynamicSetting>();
settings.Add(IntSetting);
settings.Add(StringSetting);
settings.Add(DoubleSetting);
foreach(DynamicSetting setting in settings)
{
setting.Write();
}
UPDATE:
I could also make Value
an object
public class ObjectSetting
{
public string Section { get; set; }
public string Key { get; set; }
public object Value { get; set; }
public ObjectSetting(string section, string key, object value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
case TypeCode.Double:
//Call third-party code to write a string
break;
default:
break;
}
}
}
And it would work just like dynamic
ObjectSetting IntSetting = new ObjectSetting("Section", "Key", 1);
ObjectSetting StringSetting = new ObjectSetting("Section", "Key", "1");
ObjectSetting DoubleSetting = new ObjectSetting("Section", "Key", 1.0);
System.Collections.Generic.List<ObjectSetting> settings = new List<ObjectSetting>();
settings.Add(IntSetting);
settings.Add(StringSetting);
settings.Add(DoubleSetting);
foreach(ObjectSetting setting in settings)
{
setting.Write();
}
The simplest way is to accept Value as an object in the constructor and the setter, both of which would validate the Type against your list of valid types. Use a Switch in your Write method to determine which third-party code to call. You can store all your Settings in a single collection. Alternatively, you could write overloads for the constructor and a SetValue method. That's a little more code, but would provide design time type-checking.
Example for ISettingValue:
public interface ISettingValue
{
void Write();
}
public class StringSetting : ISettingValue
{
readonly string _data;
public StringSetting(string data) => _data = data;
public void Write()
{
//Call third-party code to write the string (value of _data).
}
}
public class IntSetting : ISettingValue
{
readonly int _data;
public IntSetting(int data) => _data = data;
public void Write()
{
//Call third-party code to write the integer (value of _data).
}
}
public class Setting
{
public string Section { get; set; }
public string Key { get; set; }
public ISettingValue Value { get; set; }
public Setting(string section, string key, ISettingValue value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
Value.Write();
}
}
Maybe something like that?
public abstract class Setting {
public abstract Type keyType { get; }
public string Key { get; protected set; }
public object value { get; protected set; }
protected abstract Action writer { get; }
public void Write() => writer();
}
public class Setting<T> : Setting {
public override Type keyType => typeof(T);
protected override Action writer => () => typeWriter(Value);
public string Section { get; set; }
public T Value {get; set;}
private Action<T> typeWriter { get; }
public Setting(string section, string key, T value, Action<T> writer) {
Section = section;
Key = key;
this.value = Value = value;
typeWriter = writer;
}
}
public class Usage {
private List<Setting> settings = new List<Setting>() {
new Setting<double>("", "x", 10, n => Debug.WriteLine(n % 4)),
new Setting<string>("", "y", "abc", s => Debug.WriteLine(s.ToUpper())),
new Setting<bool>("", "z", true, b => Debug.Write(!b)),
};
public Usage() {
foreach (var s in settings) {
Debug.Write($"{s.keyType.Name} {s.Key} =");
s.Write();
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.