November 10, 2018

ThreadPool Extensions

A better more versatile way to do this is to use Task<> objects
public static class ThreadpoolExtensions
{
    // Execute a method/procedure on the thread pool
    // The state parameters allow you to pass parameters into the thread routine 
    public static bool ExecuteOnThreadPoolThread<T>(this Action<T> threadRoutine, T args)
    {
        return ThreadPool.QueueUserWorkItem(s => threadRoutine((T)s), args);
    }

    // Execute a method/procedure on the thread pool
    public static bool ExecuteOnThreadPoolThread(this Action threadRoutine)
    {
        return ThreadPool.QueueUserWorkItem((obj) => threadRoutine());
    }
}

SImple Application Settings Manager

Heres a quick class to read and write settings to the application config file
// A Minimal class to read and write settings directly to the application 
// config file with NO write permission constraints. It does keep a separate
// copy of the config file for each user
// Only Key/Value style settings can be written, and string ones only at that but
// converting most simple types to and from a string is trivial.
public class SettingsManager : ISettingsManager
{
    public string ReadSetting(string key)
    {
        try
        {
            var appSettings = ConfigurationManager.AppSettings;
            var result = appSettings[key] ?? string.Empty;
            return result;
        }
        catch (ConfigurationErrorsException ex)
        {
            Trace.WriteLine("Configuration file exception : " + ex);
        }
        return string.Empty;
    }

    public void WriteSetting(string key, string value)
    {
        try
        {
            var configFile = ConfigurationManager.OpenExeConfiguration(
                ConfigurationUserLevel.None);
            var settings = configFile.AppSettings.Settings;
            if (settings.Count == 0 | settings[key] == null)
            {
                settings.Add(key, value);
            }
            else
            {
                settings[key].Value = value;
            }
            configFile.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection(
                configFile.AppSettings.SectionInformation.Name);
        }
        catch (ConfigurationErrorsException ex)
        {
            Trace.WriteLine("Configuration file exception : "+ ex);
        }
    }

October 10, 2018

July 5, 2018

Use of gcAllowVeryLargeObjects

To allow he creation of very large arrays, lists etc. insert
<configuration>  
  <runtime>  
    <gcAllowVeryLargeObjects enabled="true" />  
  </runtime>  
</configuration>
in the application config file. This only works for 64 bit applications! This could also cause problems when unit testing because you need to ensure your test runner is running in 64 bit mode with the given entry within the test runner's config file.

February 13, 2018

Example of the Visitor Pattern


A simple but non-contrived example of the Visitor pattern. Here are the main classes.

// Interface for the visiting system permit populator
public interface IPopulatorVisitor
{
    void PopulateVisit(ISet<int> permitSystemsSet);
}

public interface IPermitSystems
{
    void AcceptPopulator(IPopulatorVisitor populatorVisitor);

    bool PermitRequired(int systemId);
}

// This is the Visitor target
// It stores a set of systems that require a permit for entry
public class PermitSystems : IPermitSystems
{
    HashSet<int> _permitRequiredSystemIds = new HashSet<int>();

    // Accept Visitors here
    public void AcceptPopulator(IPopulatorVisitor populatorVisitor)
    {
        populatorVisitor.PopulateVisit(_permitRequiredSystemIds);
    }

    public bool PermitRequired(int systemId)
    {
        bool res = _permitRequiredSystemIds.Contains(systemId);
        return res;
    }
}

The Visitor class, this has removed the responsibility for deserialising the permit data from the the PermitSystems class. In this case the data is stored in 'JSonl' form, but it could be stored in other formats and a different visitor would be provided

public class PermitSystemsJsonlDeserialiserVisitor 
    : IPopulatorVisitor
{
    FileInfo _jsonlFilePath;

    public void Initialise(string jsonlFilePath)
    {
        _jsonlFilePath = new FileInfo(jsonlFilePath);
    }

    public void PopulateVisit(ISet<int> permitSystemsSet)
    {
        List permitReqdSystems;
        if (_jsonlFilePath.TryLoadFromJson(out permitReqdSystems))
        {
            if (permitReqdSystems != null)
            {
                PopulateImpl(permitSystemsSet, permitReqdSystems);
            }
        }
    }

    private static void PopulateImpl(ISet<int> permitSystemsSet, 
        List permitReqdSystems)
    {
        foreach (var sys in permitReqdSystems)
        {
            Trace.WriteLine(" Permit required for id=" + sys.id + " name=" + sys.name +
                            " permitRequired=" + sys.permitRequired);
            permitSystemsSet.Add(sys.id);
        }
    }
}
Some sample code to bring it all together
[Test]
public void PermitSystemsExperiment()
{
    IPermitSystems permitSystems = new PermitSystems();
    PermitSystemsJsonlDeserialiserVisitor jdv = new PermitSystemsJsonlDeserialiserVisitor();
    jdv.Initialise(TestFilePaths.PermitRequiredSystemsJSonFilePath);
    permitSystems.AcceptPopulator(jdv);

    Assert.That(true == permitSystems.PermitRequired(19054));
    Assert.That(false == permitSystems.PermitRequired(26));
}

September 13, 2017

CSV Files with Linq

An example of using Linq to parse a CSV file and write data to a TSV file. The beauty of the approach shown here is the file is read one line at a time when parsing, you do not have to load the whole file to process the data, and written one line at a time when writing. Here is a sample piece of the CSV file (note the first line is a header line not a data line):
id,edsm_id,name,x,y,z,population,is_populated,government_id,government,allegiance_id,allegiance,state_id,state,security_id,security,primary_economy_id,primary_economy,power,power_state,power_state_id,needs_permit,updated_at,simbad_ref,controlling_minor_faction_id,controlling_minor_faction,reserve_type_id,reserve_type
17,60,"10 Ursae Majoris",0.03125,34.90625,-39.09375,0,0,176,None,5,None,80,None,16,Low,10,None,,,,0,1497906646,"10 Ursae Majoris",,,,
24,12009,"11 Bootis",-49.40625,285.25,65.21875,0,0,176,None,5,None,80,None,16,Low,10,None,,,,0,1474116394,"11 Bootis",,,,
26,13308,"11 Mu Aurigae",-30,0.75,-150.03125,0,0,176,None,5,None,80,None,16,Low,10,None,,,,0,1497806946,,,,,


Want to parse some of these lines into this structure:
public class BaseSystemRaw
{
    public int id { get; set; }
    public string name { get; set; }
    public float x { get; set; }
    public float y { get; set; }
    public float z { get; set; }

    public override string ToString()
    {
        return "id=" + id + ", name=" + name + 
               ", location=( " + x + ", " + y + ", " + z + " )";
    }
}
Here is a test harness:
[ TestFixture ]
class ParseCsvFilesWithLinqTests
{
    [ Test ]
    public void ParseCsvFileTest()
    {
        // Skip(1) will skip the header line
        // This commented out version will only use the first 10 lines,
        // great for debugging
        // var baseSystemRaws = File.ReadLines(TestFilePaths.SystemsFilePath).
        //     Take(10).Skip(1).Select(line => ExtractBaseSystemRaw(line));
        var baseSystemRaws = File.ReadLines( TestFilePaths.SystemsFilePath ).
                Skip( 1 ).Select( line => ExtractBaseSystemRaw( line ) );
        DoSomethingWith( baseSystemRaws );
    }

    BaseSystemRaw ExtractBaseSystemRaw(
        string line )
    {
        var parts = line.Split( ',' );
        var sysRaw = new BaseSystemRaw();
        int tmp;
        if ( int.TryParse( parts[ 0 ], out tmp ) )
        {
            sysRaw.id = tmp;
        }
        // Ignore parts[1] edsm_id
        sysRaw.name = parts[ 2 ].Trim().Replace( "\"", "" );
        float ftmp;
        if ( float.TryParse( parts[ 3 ], out ftmp ) )
        {
            sysRaw.x = ftmp;
        }
        if ( float.TryParse( parts[ 4 ], out ftmp ) )
        {
            sysRaw.y = ftmp;
        }
        if ( float.TryParse( parts[ 5 ], out ftmp ) )
        {
            sysRaw.z = ftmp;
        }
        // Ignore other parts
        return sysRaw;
    }

    private void DoSomethingWith(
        IEnumerable<BaseSystemRaw> baseSystemRaws )
    {
        foreach ( var entry in baseSystemRaws )
        {
            Trace.WriteLine( entry );
        }
    }
}
Now write the data to a TSV file.
[ TestFixture ]
class WriteTsvFilesWithLinqTests
{
    [ Test ]
    public void WriteTsvFileTest()
    {
        const string separator = "\t";
        var headers = new[] { "Id", "System", "x", "y", "z" };
        // Skip(1) will skip the header line
        // This version will only use the first 4 lines, great for debugging, 
        // remove the Take(4) to process the whole file
        var baseSystemRaws = File.ReadLines( TestFilePaths.SystemsFilePath ).
            Take(4).Skip(1).Select( line => ExtractBaseSystemRaw( line ) );
        
        // Use Enumerable.Concat to add the header string
        File.WriteAllLines( TestFilePaths.BaseSystemsTsvFilePath,
            Enumerable.Concat( new[] { string.Join( separator, headers ) },
                baseSystemRaws.Select(sys => sys != null ? 
                    CoreSystemRawToTsv( separator, sys ) : "")));
    }

    private string CoreSystemRawToTsv(
        BaseSystemRaw sys )
    {
        string line = string.Join( "\t", sys.id, sys.name, sys.x.ToString( "0.0000" ),
            sys.y.ToString( "0.0000" ), sys.z.ToString( "0.0000" ) );
        return line;
    }
}

September 5, 2017

C# HashSet

Best to demonstrate what some of the methods do with some unit tests. In particular what does 'SymmetricExceptWith' do?
[ TestFixture ]
public class HashSetTests
{
    private HashSet<int> integerSet1;
    private HashSet<int> integerSet1Copy;
    private HashSet<int> integerSet2;

    [ SetUp ]
    public void Setup()
    {
        integerSet1 = new HashSet<int> { 1, 2, 3 };
        integerSet2 = new HashSet<int> { 2, 3, 4 };
        integerSet1Copy = new HashSet<int> { 2, 3, 1 };
    }

    [ Test ]
    // The SetEquals method ignores duplicate entries and 
    // the order of elements in the other parameter.
    public void SetEqualsTest()
    {
        var integerList = new List<int> { 2, 3, 1, 3, 2 };

        Assert.That( !integerSet1.SetEquals( integerSet2 ) );
        Assert.That( integerSet1.SetEquals( integerSet1Copy ) );
        Assert.That( integerSet1.SetEquals( integerList ) );
    }

    [ Test ]
    public void IntersectWithTest() // All elements common to both sets
    {
        integerSet1.IntersectWith( integerSet2 );
        Assert.That( !integerSet1.Contains( 1 ) );
        Assert.That( integerSet1.Contains( 2 ) );
        Assert.That( integerSet1.Contains( 3 ) );
        Assert.That( !integerSet1.Contains( 4 ) );
    }

    [ Test ]
    public void UnionWithTest() // All elements in both sets
    {
        integerSet1.UnionWith( integerSet2 );
        Assert.That( integerSet1.Contains( 1 ) );
        Assert.That( integerSet1.Contains( 2 ) );
        Assert.That( integerSet1.Contains( 3 ) );
        Assert.That( integerSet1.Contains( 4 ) );
    }

    [ Test ]
    public void SymmetricExceptWithTest() // All elements not common to both sets
    {
        integerSet1.SymmetricExceptWith( integerSet2 );
        Assert.That( integerSet1.Contains( 1 ) );
        Assert.That( !integerSet1.Contains( 2 ) );
        Assert.That( !integerSet1.Contains( 3 ) );
        Assert.That( integerSet1.Contains( 4 ) );
    }
}