title: Can I override ToString() for classes in a public API?
body: <p>I'm writing a tool that interfaces with an API for another piece of software. Part of my tool will need to generate reports about the various objects found through the API, and I want these reports to contain simple strings that identify each object. By default I plan to use ToString() to generate the string for each object. However, not surprisingly I've found that the default ToString() implementations in this API aren't to descriptive.</p>
  
  <p>Initially I was thinking of doing something like the code below with a long Switch statement. Although this would most likely become unmanageably long.</p>
  
  <pre><code>public string GetAPIObjectDescrition(object obj)
  {
       Type t = obj.GetType();
  
       Switch(t)
       { 
           Case typeof(SomeAPIType):
               SomeAPIType x = (SomeAPIType)obj;
               return  x.SomeProperty;             
  
  
           Case typeof(SomeOtherAPIType):
               SomeOtherAPITypex = (SomeOtherAPIType)obj;
               return  x.SomeOtherProperty;
  
           default:
               return x.ToString();
       }
  } 
  </code></pre>
  
  <p>Next I tried using extension methods (see the code below). CustomObjectDescription() worked as expected, but when I tried to call ToString() it just returns the default ToString() results. I've never used extension methods before so I could be completely off base thinking something like this is even possible.</p>
  
  <p>I can't guarantee that there will be a CustomObjectDescription() extension for every Type encountered in the API, so if I take this route I would end up having to use reflection each time to check if the current object has a GetObjectDescription() extension. I'd like to avoid using reflection if at all possible.</p>
  
  <pre><code>public static class APIObjectDescriptionExtensions
  {
      public static string ToString(this APIObject element)
      {
          return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
      }
  
      public static string CustomObjectDescription(this APIObject element)
      {
          return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
      }
  }
  </code></pre>
  
  <p>Does anyone have any other suggestions on how I should approach this problem? I'd prefer a solution where the code for each API Type is independent from one another (no giant Switch statement). </p>
  
  <p>Also if possible I'd like the description string code for one type to inherit to sub types unless those types have their own unique description string code.</p>
  
  <p>I think there might be a better solution that involves creating custom TypeConverters or maybe overriding/extending System.Convert.ToString()?</p>
  
  <hr>
  
  <p><strong>Update</strong></p>
  
  <p>I think the example below might help clarify what I'm trying to do. Ultimately I want to be able to take any arbitrary class from this API, the Type of which is not known until run time, and generate a description string. If the Type has my custom extension method then it should be used, otherwise the code should fall back on plain old ToString().</p>
  
  <pre><code>    public static string GetDataDescription(object o)
      {
          //get the type of the input object
          Type objectType = o.GetType();
  
          //check to see if a description extension method is defined
          System.Reflection.MethodInfo extensionMethod = objectType.GetMethod("MyDescriptionExtensionMethod");
  
          if (extensionMethod != null)
          {
              //if a description extension method was found returt the result
              return (string)extensionMethod.Invoke(o, new object[] { });
          }
          else
          {
              //otherwise just use ToString();
              return o.ToString();
          }
      }
  </code></pre>
  
  <p>This code above doesn't work though because extension methods <a href="http://social.msdn.microsoft.com/Forums/en/vcsharp2008prerelease/thread/4842bf63-aa8b-4f40-9a88-04dfe1e89429" rel="nofollow">aren't found by GetMethod()</a>.</p>