title: What's the accepted way to handle values that can be different data types in C#?
body: <p>I'm basically reading a config file</p>
  
  <p><code>[Section]
  Key=value</code></p>
  
  <p>Where the <code>value</code> can be either a string, an integer, a double, or a boolean value.  </p>
  
  <p>While working in this context, I have a class that looks like this...</p>
  
  <pre><code>public class Setting
  {
      public string Section {get; set;}
      public string Key {get; set;}
      public &lt;string, int, double, or bool&gt; Value {get; set;}
  
      public Setting(string section, string key, &lt;string, int, double, or bool&gt; 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.
          //...
      }
  }
  </code></pre>
  
  <p>In this situation, what is the accepted way to handle the <code>Value</code> property of this class?</p>
  
  <p>In addition, I'd like to be able to store a bunch of these objects in an Array, List, or other types of collections.</p>
  
  <hr>
  
  <p>UPDATE:<br>
  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 <code>Value</code></p>
  
  <hr>
  
  <p>UPDATE:<br>
  One thought was to use generics, and have a class like this...</p>
  
  <pre><code>public class Setting&lt;T&gt;
  {
      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;
          }
      }
  }
  </code></pre>
  
  <p>But then I'd only be able to store a single type of setting in a List.</p>
  
  <pre><code>System.Collections.Generic.List&lt;Setting&lt;string&gt;&gt; settings = new List&lt;Setting&lt;string&gt;&gt;();
  </code></pre>
  
  <p>So I'd have to have a list for each type of setting.</p>
  
  <hr>
  
  <p>UPDATE:<br>
  Another option might be to use and interface, and classes for each type of setting that implement the interface...</p>
  
  <pre><code>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.
      }
  }
  </code></pre>
  
  <p>But that seems like a lot of duplicate code, so making changes in the future might be error prone.</p>
  
  <hr>
  
  <p>UPDATE:<br>
  Another option, is to make <code>Value</code> a dynamic type.</p>
  
  <pre><code>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;
          }
      }
  }
  </code></pre>
  
  <p>Then I can create a bunch of DynamicSetting objects, and store them in a collection like I want.</p>
  
  <pre><code>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&lt;DynamicSetting&gt; settings = new List&lt;DynamicSetting&gt;();
  
  settings.Add(IntSetting);
  settings.Add(StringSetting);
  settings.Add(DoubleSetting);
  
  foreach(DynamicSetting setting in settings)
  {
      setting.Write();
  }
  </code></pre>
  
  <hr>
  
  <p>UPDATE:<br>
  I could also make <code>Value</code> an object</p>
  
  <pre><code>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;
          }
      }
  }
  </code></pre>
  
  <p>And it would work just like dynamic</p>
  
  <pre><code>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&lt;ObjectSetting&gt; settings = new List&lt;ObjectSetting&gt;();
  
  settings.Add(IntSetting);
  settings.Add(StringSetting);
  settings.Add(DoubleSetting);
  
  foreach(ObjectSetting setting in settings)
  {
      setting.Write();
  }
  </code></pre>