Class Seperation vs Polymorphism I'm interested in optimizing my code. Can someone help me understand the best way to trim this code down with DRY methodology?

So I've got these two classes here preforming WMI queries on two separate Win32 classes. My questions are:


Should I keep them separated in different classes based on the Win32 class for organizational purposes?
Should I use a parent partial class and split these into different files?
Should I use methods with optional parameters or overloads in order to reduce the number of classes here?
Why is the selected method best?




public class Win32OperatingSystem
{
    public ulong GetFreePhysicalMemory()
    {
        return GetProperty("FreePhysicalMemory");
    }

    public ulong GetTotalVirtualMemorySize()
    {
        return GetProperty("TotalVirtualMemorySize");
    }

    public ulong GetFreeVirtualMemory()
    {
        return GetProperty("FreeVirtualMemory");
    }

    private ulong GetProperty(string propertyName)
    {
        ManagementObjectSearcher moSearcher = new ManagementObjectSearcher
            ("SELECT " + propertyName + " FROM Win32_OperatingSystem");
        using (var enu = moSearcher.Get().GetEnumerator())
        {
            if (!enu.MoveNext()) return 0;
            return BytesToMegaBytes((ulong)enu.Current[propertyName]);
        }
    }

    private ulong BytesToMegaBytes(ulong bytes)
    {
        return bytes / (ulong)1024;
    }
}

public class Win32ComputerSystem
{
    public string GetName()
    {
        return GetProperty("Name");
    }

    public string GetManufacturer()
    {
        return GetProperty("Manufacturer");
    }

    public string GetModel()
    {
        return GetProperty("Model");
    }

    private string GetProperty(string propertyName)
    {
        ManagementObjectSearcher moSearcher = new ManagementObjectSearcher
            ("SELECT " + propertyName + " FROM Win32_ComputerSystem");
        using (var enu = moSearcher.Get().GetEnumerator())
        {
            if (!enu.MoveNext()) return "Unable to retrieve " + propertyName + " from Win32_ComputerSystem!";
            return enu.Current[propertyName].ToString();
        }
    }
}


Questions in this series

This is the first question in the series.

First iteration of DRY refactoring

Second iteration of DRY refactoring.

Genericizing PropertyValues
How about leveraging Enum.ToString()?

Given these two enums:

public enum Win32OperatingSystem
{
    FreePhysicalMemory,
    TotalVirtualMemorySize,
    FreeVirtualMemory
}

public enum Win32ComputerSystem
{
    Name,
    Manufacturer,
    Model
}


Now you can have a simple method:

    public ulong SelectWin32Property(Win32OperatingSystem property)
    {
        var propertyName = property.ToString();
        var moSearcher = new ManagementObjectSearcher
            ("SELECT " + propertyName + " FROM Win32_OperatingSystem");
        using (var enu = moSearcher.Get().GetEnumerator())
        {
            if (!enu.MoveNext()) return 0;
            return BytesToMegaBytes((ulong)enu.Current[propertyName]);
        }
    }


If you wanted an overload that takes a Win32ComputerSystem parameter, you'd have to deal with the different return value:

    public string SelectWin32Property(Win32ComputerSystem property)
    {
        var propertyName = property.ToString();
        var moSearcher = new ManagementObjectSearcher
            ("SELECT " + propertyName + " FROM Win32_ComputerSystem");
        using (var enu = moSearcher.Get().GetEnumerator())
        {
            if (!enu.MoveNext()) return "Unable to retrieve " + propertyName + " from Win32_ComputerSystem!";
            return enu.Current[propertyName].ToString();
        }
    }


The easiest would probably be to box the numeric types into a string, so all overloads would return a string representation of their values. This might not be practical, but at least you don't need to write a new method nor to change your interface to support a new property.

Alternatively you could box results in an object, but that wouldn't be pretty, I'd much prefer dealing with a string than exposing object.

The ideal would be to avoid boxing the numeric return types altogether, so the methods have to live in separate classes - this is where generics come handy:

public abstract class Win32QueryBase&lt;TResult, TProperty&gt;
{
    public abstract TResult SelectWin32Property(TProperty property);
}


This can be implemented by this class:

public class Win32OperatingSystemQuery : Win32QueryBase&lt;ulong, Win32OperatingSystem&gt;
{
    public override ulong SelectWin32Property(Win32OperatingSystem property)
    {
        // ...
    }
}


And this class:

public class Win32ComputerSystemQuery : Win32QueryBase&lt;string, Win32ComputerSystem&gt;
{
    public override string SelectWin32Property(Win32ComputerSystem property)
    {
        // ...
    }
}