Thoughts from Dan Miser RSS 2.0
 Thursday, January 11, 2007
In Delphi, if you want an array of integers, indexed by an enumeration, you simply do this:

type
  TSuit = (Clubs, Spades, Hearts, Diamonds);
var
  CardCount: array[TSuit] of integer;
...
  CardCount[Clubs] := 13;

In .NET, however, you can not specify an enumerated type as the indexer into an array, so a line by line conversion to C# will not work. Instead, you need to create an entirely new helper class to make the calling code more readable (i.e. without putting casting code in all of the uses of the indexer). Furthermore, you can't use the code below in a Compact Framework (CF) application, because Enum.GetValues() and Enum.GetNames() aren't implemented in the CF libraries.



class Program

{

    static void Main(string[] args)

    {

        CardCounter cc = new CardCounter();

        cc[Suit.Clubs] = 13;

    }

}

 

public enum Suit {Clubs, Spades, Hearts, Diamonds};

 

public class CardCounter

{

    private static int enumCount = Enum.GetValues(typeof(Suit)).Length;

    private int[] counts = new int[enumCount];

 

    public int this[Suit suit]

    {

        get { return counts[(int)suit]; }

        set { counts[(int)suit] = value; }

    }

}

Thursday, January 11, 2007 8:47:32 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET
 Wednesday, January 10, 2007
XML serialization is handy, but it does lack some power. For example, if you have class inheritance, and you want a property of the child class to have a different name than the one given to it by the parent, you will get an error at run-time when trying to serialize the object: "Member 'Derived.Name' hides inherited member 'Base.Name', but has different custom attributes.".

Assume you have a class structure like this:

public abstract class Base

{

    private int id;

    private string name;

 

    [XmlElement("id")]

    public int Id

    {

        get { return id; }

        set { id = value; }

    }

 

    [XmlElement("name")]

    public virtual string Name

    {

        get { return name; }

        set { name = value; }

    }

}

 

public class Derived : Base

{

    [XmlElement("newName")]

    public override string Name

    {

        get { return base.Name; }

        set { base.Name = value; }

    }

}

To see the error, call it like this:

static void Main(string[] args)

{

    Derived d = new Derived();

    d.Id = 23;

    d.Name = "Dan";

    string xml = GetXMLFromObject(d);

    Console.WriteLine(xml);

}

Download the sample application here to play with it.

Wednesday, January 10, 2007 11:57:12 AM (Central Standard Time, UTC-06:00)  #    Comments [1] -
.NET | XML
 Tuesday, January 09, 2007
Some times, it is better to have a minimal format for your XML file. When using XmlSerializer, it likes to add the standard XML namespaces to the generated XML file. If you want those gone, use code like this:

public static string GetXMLFromObject(object obj)

{

    XmlSerializer xs = new XmlSerializer(obj.GetType());

 

    // Set up chain of writers

    StringBuilder sb = new StringBuilder();

    using (XmlTextWriter writer = new XmlTextWriter(new StringWriter(sb)))

    {

        writer.Formatting = Formatting.Indented;

 

        // Remove standard namespace attributes

        XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();

        xsn.Add(string.Empty, string.Empty);

        xs.Serialize(writer, obj, xsn);

    }

 

    return sb.ToString();

}

The key is to create an XmlSerializerNameSpaces object, populate it with empty strings, and then pass it to the XmlSerizliazer. The result is a more compact XML file. Note that this works, despite the comment in the documentation explicitly saying that it isn't supported.

You can also use this class to add your own custom namespaces. This could be useful to prefix certain elements with a certain namespace.

Tuesday, January 09, 2007 9:52:45 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | XML
 Monday, January 08, 2007
While the XmlIgnore/Specified pattern to control serialization is very useful, it could be overkill for simpler serialization scenarios.

When you create an object with a bool field, that field is initialized and defaulted to the value of false. Under normal conditions, this value will get serialized every time. However, what if we only care about capturing that value when the value is true? It turns out that we can use DefaultValueAttribute. The first thing that may stand out to you is that this attribute lives in the System.ComponentModel namespace, and not in an XML namespace. The online help also mentions that this is used for visual designers and code generators. XmlSerializer also uses this attribute to decide whether or not to stream the value during serialization, since it's really a form of a code generator (more on that in a later post). If the value of the field or property matches the value that you specify in the DefaultValueAttribute, then that property will not be streamed.

Using an XmlAttributeAttribute, you can specify that a certain property will be expressed as an XML attribute instead of an XML element. To demonstrate both of these concepts, see the following code:

public class Url

{

    [XmlAttribute("address")]

    public string Address;

    [XmlAttribute("primary"), DefaultValue(false)]

    public bool Primary;

    public Url()

    {

   }

}

static void Main(string[] args)

{

    Url u = new Url();

    u.Address = "http://testing/";

    string xml = GetXMLFromObject(u);

    Console.WriteLine(xml);

}

This produces roughly the following output (XML namespace information is stripped here. I will show how to do this in code with a future post). Notice that the Primary attribute is not generated because it matches the DefaultValue.

<?xml version="1.0" encoding="utf-16"?>

<Url address="http://testing/" />

Monday, January 08, 2007 9:09:43 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET | XML
 Friday, January 05, 2007
David Hervieux posted a link to some Serialization FAQs in a comment to my last post. This material is good, and actually forced me to go back through what I wanted to cover, since I didn't want to just add posts that duplicate what can be found easily on the web. I'll still move forward with a few items in XML serialization that I think are unique.

The XMLIgnore attribute is used to tell the XmlSerializer that this field is transient, and should not be (de)serialized. The most typical use for this would be to mark calculated fields with this attribute. This is an easy customization that helps your serialization process, but it leaves a bit to be desired. It's an "all or nothing" approach, where the property is either streamed or not.

This MSDN article hints at what to do to get more fine-grained control of this aspect of serialization. Basically, you create a public boolean field or property named propertyNameSpecified for the property you want to control. The XmlSerializer uses this convention to determine whether or not to include the associated property for serialization. Since this new Specified field will be eligible for serialization, be sure to mark it with the XmlIgnore attribute to prevent it from being serialized.

A very simple code listing showing how this all fits together:

    public class Player

    {

        private int number;

        private string name;

        [XmlElement("jerseyNumber")]

        public int Number

        {

            get { return number; }

            // You could add more logic here to only set NumberSpecified based on some criteria

            set { number = value; NumberSpecified = true; }

        }

        [XmlElement("playerName")]

        public string Name

        {

            get { return name; }

            set { name = value; }

        }

        [XmlIgnore]

        public bool NumberSpecified;

    }

The downsides to using this techniques are:
  • It requires another field, and some custom logic to make this work.
  • It requires that the Specified field be marked as public, exposing it to consumers of the library. There is no real reason why the XmlSerializer couldn't use reflection to get at a non-public member.
  • If you use a property, it must be a full read-write property. A read-only property could very well suffice here, and make your code easier to maintain.

      Download the very simple sample showing this behavior here.

    • Friday, January 05, 2007 1:37:20 PM (Central Standard Time, UTC-06:00)  #    Comments [2] -
      .NET | XML
       Wednesday, December 27, 2006
      Serializing between .NET objects and XML files, and vice versa, is extremely easy, yet flexible and powerful. I'll be blogging a few entries about this topic in the days to come. This entry will set the stage, showing the basics of XML serialization.

      Assume you have a (stripped down) class definition like this:

          public class Player

          {

              [XmlElement("jerseyNumber")]

              public int Number { get; set; }

              [XmlElement("playerName")]

              public string Name { get; set; }

          }

      And you wanted to read/write an XML file that looked like this:

      <Player>

        <jerseyNumber>23</jerseyNumber>

        <playerName>Dan</playerName>

      </Player>

      The key to making this happen is the XmlSerializer class. This is the class that will convert between public properties and XML elements. You can also decorate your class with simple attributes to coerce your class into generating custom XML (i.e. XML attributes, hide or rename elements, etc.).

      Here are a couple of helper methods, and a sample that uses them to show you how all of this comes together.

              static string GetXMLFromObject(object obj)

              {

                  XmlSerializer ser = new XmlSerializer(obj.GetType());

       

                  StringBuilder sb = new StringBuilder();

                  using (XmlTextWriter writer = new XmlTextWriter(new StringWriter(sb)))

                  {

                      writer.Formatting = Formatting.Indented;

                      ser.Serialize(writer, obj);

                      return sb.ToString();

                  }

              }

       

              static object CreateObjectFromXML(string xml, Type xmlType)

              {

                  XmlSerializer ser = new XmlSerializer(xmlType);

                  object obj = null;

                  using (StringReader reader = new StringReader(xml))

                  {

                      obj = ser.Deserialize(reader);

                  }

                  return obj;

              }

       

              static void Main(string[] args)

              {

                  Player p = new Player();

                  p.Number = 23;

                  p.Name = "Dan";

                  string xml = GetXMLFromObject(p);

                  Console.WriteLine(xml);

                  Console.WriteLine();

       

                  Player q = (Player)CreateObjectFromXML(xml, typeof(Player));

                  Console.WriteLine(q.Number + " --> " + q.Name);

                  Console.ReadLine();

              }

      Other references:
      XML Serialization in the .NET Framework

      Wednesday, December 27, 2006 11:05:11 AM (Central Standard Time, UTC-06:00)  #    Comments [1] -
      .NET | XML
       Monday, December 18, 2006
      It looks like lots of changes are going on here. First off, I am now working in C# full-time since I took a job with SpiderLogic. I think this is going to be a great opportunity for me to expand and grow again. I doubt I will ever be out of Delphi completely, but my new focus is definitely going to be on .NET. As such, I contacted DelphiFeeds to tell them to use just my Delphi category. Someone contacted me after a VS.NET post and mentioned that it seemed strange to see that on the Delphi feed, and I agreed. I don't want to clutter a very good Delphi resource up with blog posts about a competing IDE and/or language. However, if you like what you read here, I would encourage you to subscribe to my main feed, too.

      The other change is on my blog. With prompting from Steve Trefethen, I made the switch to dasBlog. I had set dasBlog up for our internal blog at my last place of employment, and it worked great. I got tired of the lack of options that .Text provided, so I felt I had to do something. dasBlog provides a couple of features that I really wanted, like searching and better spam prevention. In addition, it's actively being developed.

      Converting was fairly painless. I read a post by Scott Hanselman about migrating to dasBlog, and from there I found some code to help automate the conversion. There are several dead links out there, so finding this one was a definite time saver. I changed the code slightly to get categories out of .Text and into dasBlog. I changed the main SQL statement to the one below, and then just added a line of code to add that category information to the dasBlog conversion code. This works for me because I didn't use multiple categories for a post.

      
      SELECT 
        blog_Content.ID, blog_Content.Title, blog_Content.DateAdded, blog_Content.SourceUrl, blog_Content.PostType, 
        blog_Content.Author, blog_Content.Email, blog_Content.SourceName, blog_Content.BlogID, blog_Content.Description, 
        blog_Content.DateUpdated, blog_Content.TitleUrl, blog_Content.Text, blog_Content.ParentID, blog_Content.FeedBackCount, 
        blog_Content.PostConfig, blog_Content.EntryName, blog_LinkCategories.Title AS CategoryTitle
      FROM blog_Content 
        LEFT OUTER JOIN blog_Links ON blog_Links.PostID = blog_Content.ID 
        LEFT OUTER JOIN blog_LinkCategories ON blog_Links.CategoryID = blog_LinkCategories.CategoryID
      

      I was worried about old URLs that were used from my .Text blog, but the later versions of dasBlog already do URL rewriting to make that transition absolutely seamless. I also use w.bloggar for writing my entires, so I had to change some settings to get that to work with dasBlog. Lastly, I updated my RSS feed to use FeedBurner.

      All in all, I'm quite happy with how things turned out. If you see any problems, please feel free to let me know.

      Monday, December 18, 2006 9:42:22 AM (Central Standard Time, UTC-06:00)  #    Comments [2] -
      Delphi
       Wednesday, December 13, 2006
      I just finished reading this book by Jimmy Nilsson, and I have a mixed review of it. The general consensus (e.g. see here and here) out there is that this book is one of the most fantastic books out there on how to architect systems using C#. I do agree that the book is well-written, with a very unique insight into the thoughts and decisions to make along the way in designing a robust application from an OO viewpoint. It got me thinking about how I view TDD and architecture from a domain model perspective.

      The negative for this book outweighs the benefits, in my opinion. The fact that there is no sample/reference application leaves the reader frustrated. If the design techniques can't even be proven in a simple application that was discussed over 450 pages, how can one have faith to apply the techniques in their own production applications? I searched on the book's forum, but the general attitude there is "If you need a sample, you can't understand all the decisions made to create your own application". My reply to that is "Hogwash". As mentioned earlier, 450 pages were used to talk about why certain architectural decisions were made.

      All in all, I would skip this book until the major deficiency of no sample application is fixed.

      Wednesday, December 13, 2006 10:42:00 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
      .NET
      Navigation
      Archive
      <January 2007>
      SunMonTueWedThuFriSat
      31123456
      78910111213
      14151617181920
      21222324252627
      28293031123
      45678910
      About the author/Disclaimer

      Disclaimer
      The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

      © Copyright 2008
      Dan Miser
      Sign In
      Statistics
      Total Posts: 306
      This Year: 21
      This Month: 0
      This Week: 0
      Comments: 603
      All Content © 2008, Dan Miser
      DasBlog theme 'Business' created by Christoph De Baene (delarou)