September 20, 2011

Delegating Events & Event Serialisation Problems

Delegating an event to an underlying class:
...
private Helper helper;

// Normally implementation of add/remove are hidden but it is still possible to define them explicitly
public event EventHandler SomethingChanged
{
 add
 {
  this.helper.SomethingChanged += value;
 }
 remove
 {
  this.helper.SomethingChanged -= value;
 }
}
From the Event Accessors article by Stephen Toub, we get the following advice:

The trouble with events when it comes to .NET serialization is that they're backed by a private delegate field, and delegates are serializable. When you create a delegate for an instance method, the delegate maintains a reference to the instance on which to call that method, so when you serialize an object that contains an event, the formatter, while walking the object graph, will continue on down through the delegate attempting to serialize any instances registered with that delegate. A solution is to mark the backing store for the event with [NonSerializable]

Here is an example of the suggested solution:
[NonSerializable]
private EventHandler _myEvent;

September 14, 2011

Using Attributes for Property Meta Data

Another simple example of using Attributes and reflection. This time to place meta data on a property
[AttributeUsage(AttributeTargets.Property)]
[DebuggerDisplay("Name={Name}, Descr={Description}, Min={Min}, Max={Max}")]
public class DoublePropertyMetaData
    : System.Attribute
{
    public string Name { get; set; }
    public string Description { get; set; }
    public double Min { get; set; }
    public double Max { get; set; }
    public override string ToString()
    {
        string str = string.Format("Name={0}, Descr={1}, Min={2}, Max={3}", 
            Name, Description, Min.ToString(), Max.ToString());
        return str;
    }
}

public class PropertyTest
{
    [DoublePropertyMetaData(Name = "Valve Flow Rate", 
        Description = "Rate of flow through inlet valve", 
        Max = 12345.1d, Min = 0.0d)]
    public double ValveFlowRate { get; set; }
}

public class AttributesAsMetaDataTester
{
    public void Test1()
    {
        DoublePropertyMetaData propMetaData = GetDoubleMetaData(typeof(PropertyTest));
        Console.WriteLine("Result: " + propMetaData.ToString());
    }

    private static DoublePropertyMetaData GetDoubleMetaData(Type type)
    {
        PropertyInfo[] props = type.GetProperties();
        DoublePropertyMetaData[] attributes = new DoublePropertyMetaData[0];
        foreach (PropertyInfo prop in props)
        {
            attributes = (DoublePropertyMetaData[])prop.GetCustomAttributes(
                typeof(DoublePropertyMetaData), false);
        }
        return attributes[0];
    }
}

August 23, 2011

Enum and Description Attribute

Found this helper in this article EnumHelper - Getting a Friendly Description from an Enum by Grant Barrington, initially.
Found idea for the generic enum class here
Have refactored and merged them a little and added a couple of my own methods
    /// <summary>
    /// Not really an extension class but this is more readable than an extension class.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class Enum<T> 
        where T : struct, Enum
    {
        /// <summary>
        /// Parse the given string into an enum value, ignores the case of the string
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <returns>Enum value parsed from the string</returns>
        public static T Parse(string value)
        {
            return Enum<T>.Parse(value.Trim(), true);
        }

        /// <summary>
        /// Parse the given string into an enum value
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <param name="ignoreCase">Whether to ignore the case of the letters in the string when parsing</param>
        /// <returns>Enum value parsed from the string</returns>
        public static T Parse(string value, bool ignoreCase)
        {
            return (T)Enum.Parse(typeof(T), value.Trim(), ignoreCase);
        }

        /// <summary>
        /// Try to parse the given string into an enum value, ignores the case of the string. Capture any exceptions
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <param name="returnedValue">Enum value parsed from the string</param>
        /// <returns>true if the string was successfully parsed into a enum value of the given type</returns>
        public static bool TryParse(string value, out T returnedValue)
        {
            return Enum.TryParse<T>(value, true, out returnedValue);
        }

        /// <summary>
        /// Try to parse the given string into an enum value. Capture any exceptions
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <param name="ignoreCase">Whether to ignore the case of the letters in the string when parsing</param>
        /// <param name="returnedValue">Enum value parsed from the string</param>
        /// <returns>true if the string was successfully parsed into a enum value of the given type</returns>
        public static bool TryParse(string value, bool ignoreCase, out T returnedValue)
        {
            return Enum.TryParse<T>(value, ignoreCase, out returnedValue);
        }

        /// <summary>
        /// Get the enum values of the given enum type
        /// </summary>
        /// <returns>Array of the enum values in the enum type</returns>
        public static Array GetValues()
        {
            return Enum.GetValues(typeof(T));
        }

        /// <summary>
        /// Returns first description attribute of the enum value or the enum value 
        /// itself as a string if no description attribute was found
        /// </summary>
        /// <param name="enumValue">An enum value in the given enum type</param>
        /// <returns>
        /// First description attribute found of the enum value or the enum value 
        /// itself as a string if no description attribute was found
        /// </returns>
        public static string GetAsString(T enumValue)
        {
            string res = GetFirstDescriptionAttribute(enumValue);
            if (string.IsNullOrEmpty(res))
                res = enumValue.ToString();
            return res;
        }

        /// <summary>
        /// Returns first description attribute of the enum value
        /// </summary>
        /// <param name="enumValue">An enum value in the given enum type</param>
        /// <returns>
        /// First description attribute found of the enum value or null if no description attribute was found
        /// </returns>
        public static string GetDescriptionAttribute(T enumValue)
        {
            Type type = enumValue.GetType();

            MemberInfo[] memInfo = type.GetMember(enumValue.ToString());

            if (memInfo != null && memInfo.Length > 0)
            {
                object[] attrs = memInfo[0].GetCustomAttributes(
                    typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0)
                {
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }

            return null;
        }

 
    }
Now use the above helpers to demonstrate how to get the description attribute on an enum entry and how to get the best string form for an enum for entry into a listbox or something
public enum DescriptionsEnum
{
    [DescriptionAttribute("Add On")]
    AddOn,
    [DescriptionAttribute("Snap On")]
    SnapOn = 7,
    Adjacent = 2,
    Fixed = 12,
};

public void Test1()
{
    int asInt = 0;            
    foreach (var entry in Enum<DescriptionsEnum>.GetValues())
    {
        asInt = (int)entry;
        Console.WriteLine(asInt.ToString() + " " + 
            entry.ToString() + ":" + 
            Enum<DescriptionsEnum>.GetDescriptionAttribute((Enum)entry));
    }
    Console.WriteLine();
    foreach (var entry in Enum<DescriptionsEnum>.GetValues())
    {
        asInt = (int)entry;
        Console.WriteLine(asInt.ToString() + " " + 
            Enum<DescriptionsEnum>.GetAsString((Enum)entry));
    }
}
and the output of the test is
0 AddOn:Add On
2 Adjacent:
7 SnapOn:Snap On
12 Fixed:

0 Add On
2 Adjacent
7 Snap On
12 Fixed
There is also an interesting article on Enum: Binding to the Description Attribute by Deborah Kurata.
Using these helpers making something to bind to is much simpler:
Dictionary<string, int> bindToMe = new Dictionary<string, int>();
foreach (var entry in Enum.GetValues(typeof(DescriptionsEnum)))
{
    asInt = (int)entry;
    bindToMe.Add(EnumHelper.GetAsString((Enum)entry), asInt);
} 

August 22, 2011

Properties in C++/CLI

See also C++/CLI lesson here
To implement them completely inline:
virtual property bool IsWritable {
  bool get() { return isWritable_; };
  void set(bool value) { isWritable_ = value; };
}
In header file (.h) for a header+source implementation:
virtual property System::String ^Name {
  System::String ^get();
  void set(System::String^); 
}
then in the source (.cpp) file:
System::String ^ XXX::Name::get() {
  return gcnew System::String(xxx.getName().c_str());
}

void XXX::Name::set(System::String ^value) {
   ...
}
To override, in the header of derived class change the definition with an override statement:
virtual property bool DoSomething {
  bool get() override;
  bool set() override;
}

August 19, 2011

FileSystemWatcher

File system watcher hints and tips
Msdn page for it has some useful information on gotchas

Following sample code watches a file and fires events when the file "appears" or "disappears". In this case the file could "appear" when it is created or when it is renamed from an existing file and "disappear" if it is deleted or the file is renamed to something else.

This renaming issue is something to watch out for when using this class! Detecting this is a bit more subtle.
//class fields
FileSystemWatcher fileWatcher = new FileSystemWatcher();
// Target a specific file (in this case)
readonly string targetFileName = "Myfile.name";
string targetDirectory;
string fullTargetFilePath;
...
// Expose some events
public event EventHandler LockFileAppeared;
public event EventHandler LockFileDisappeared;

// Private Firing events
void FireLockFileAppeared(FileSystemEventArgs eargs)
{
  if (LockFileAppeared != null)
    LockFileAppeared(this, eargs);
}

void FireLockFileDisappeared(FileSystemEventArgs eargs)
{
  if (LockFileDisappeared != null)
    LockFileDisappeared(this, eargs);
}
...
// Initialise it
void InitialiseFileWatcher()
{
  if (Directory.Exists(this.targetDirectory))
  {
    this.fullTargetFilePath = System.IO.Path.Combine(
            LockFileDirectory, LockFileName);
    fileWatcher.Path = LockFileDirectory;
    fileWatcher.Filter = LockFileName; 
    fileWatcher.IncludeSubdirectories = false;
    fileWatcher.Renamed += new RenamedEventHandler(fileWatcher_Renamed);
    fileWatcher.Error += new ErrorEventHandler(fileWatcher_Error);
    fileWatcher.Created += new FileSystemEventHandler(fileWatcher_Created);
    fileWatcher.Deleted += new FileSystemEventHandler(fileWatcher_Deleted);
    fileWatcher.EnableRaisingEvents = true;
  }
}

// Implement a IDisposable as FileSystemWatcher is disposable
...
// Add events
void fileWatcher_Deleted(object sender, FileSystemEventArgs e)
{ // FIRED ON ANOTHER THREAD
  if (e.Name == LockFileName)
    FireLockFileDisappeared(e);
}

void fileWatcher_Created(object sender, FileSystemEventArgs e)
{ // FIRED ON ANOTHER THREAD
  if (e.Name == LockFileName)
    FireLockFileAppeared(e);
}

void fileWatcher_Renamed(object sender, RenamedEventArgs e)
{ // FIRED ON ANOTHER THREAD
  // If another file is renamed to our target file 
  if (e.Name == LockFileName)
  {
    FireLockFileAppeared(new FileSystemEventArgs(
      WatcherChangeTypes.Created, LockFileDirectory, LockFileName));
  }
  // If our target file is renamed to something else
  else if (e.OldName == LockFileName)
  {
    FireLockFileDisappeared(new FileSystemEventArgs(
      WatcherChangeTypes.Deleted, LockFileDirectory, LockFileName));
  }
}

// Misc. helpers
public string LockFilePath
{
    get { return this.fullTargetFilePath; }
}

public string LockFileDirectory
{
    get { return this.targetDirectory; }
}

Be aware that the class events are fired on another thread so if you want to update the GUI you will have to marshal any data accross. Also be aware that sometimes the events can be fired multiple times for only 1 real event.

August 12, 2011

C++/CLI Using Keyword


#using <XXX::YYY::ZZZ.dll&gt; <= Add a reference to a particular assembly, goes after precompiled header. Make sure to add the path of the referenced assembly to your C# assembly in VS via your assembly's project properties > C/C++ > General > Resolve #using References

using XXX::YYY::ZZZ::StrategyManager; <= Use a specific type (class, enum, ...) from a referenced assembly

using namespace System::Linq; <= Access all types in a namespace from a referenced assembly

August 11, 2011

Virtual Sealed Method in C++/CLI

example:
 virtual System::String^ DoSomething(...) sealed;
What does the sealed do here?
"sealed" on a function means that you can't override that method in a derived type.