I'm a little bit confused about the different ways to use methods to interact with objects in C#, particularly the major design differences and consequences between the following:
Example:
public class MyPoint
{
public double x { get; set; }
public double y { get; set; }
public double? DistanceFrom(MyPoint p)
{
if (p != null)
{
return Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));
}
return null;
}
}
If you could accomplish the desired outcome by simply placing a method in a class definition, why would a POCO combined with either a static helper class or an extension method be preferable?
You asked, "If you could accomplish the desired outcome by simply placing a method in a class definition, why would a POCO combined with either a static helper class or an extension method be preferable?"
The answer is that it depends on the situation, and if the methods in question are directly related to your class' primary concern (see single responsibility principle).
Here are some examples of where it might be a good idea to use each type of approach/method (using your code sample as a starting point).
1. Instance Methods
//This all makes sense as instance methods because you're
//encapsulating logic MyPoint is concerned with.
public class MyPoint
{
public double x { get; set; }
public double y { get; set; }
public double? DistanceFrom(MyPoint p)
{
if (p != null)
return Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));
return null;
}
}
2. Static Class Methods - An error logging example.
//Your class doesn't directly concern itself with logging implmentation;
//that's something that is better left to a separate class, perhaps
//a "Logger" utility class with static methods that are available to your class.
public double? DistanceFrom(MyPoint p)
{
try
{
if (p != null)
return Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));
return null;
}
catch(Exception ex)
{
//**** Static helper class that can be called from other classes ****
Logger.LogError(ex);
//NOTE: Logger might encapsulate other logging methods like...
//Logger.LogInformation(string s)
//...so an extension method would be less natural, since Logger
//doesn't relate to a specific base type that you can create an
//extension method for.
}
}
3. Extension Methods - An XML serialization example.
//Maybe you want to make it so that any object can XML serialize itself
//using an easy-to-use, shared syntax.
//Your MyPoint class isn't directly concerned about XML serialization,
//so it doesn't make sense to implement this as an instance method but
//MyPoint can pick up this capability from this extension method.
public static class XmlSerialization
{
public static string ToXml(this object valueToSerialize)
{
var serializer = new XmlSerializer(valueToSerialize.GetType());
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
serializer.Serialize(writer, valueToSerialize);
return sb.ToString();
}
}
//example usage
var point = new MyPoint();
var pointXml = point.ToXml(); //<- from the extension method
The rule of thumb is: