[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Best Practices for C# XML Commenting

Posted on 2005-04-19
5
Medium Priority
?
355 Views
Last Modified: 2008-01-09
I'm looking into using the C# XML documentation feature.  This is where you type the three slashes before a comment line and those comments become available for XML and HTML generation.  

Does anyone know where I might find best practices on using this feature?  It looks like it's incredibly flexible so I'm not sure where to start.  

Also, what's the main advantage?  Couldn't another developer figure out what's happening in well-documented code by actually reading the code itself?  Is this mainly so that information can be gleaned directly from an assembly?
0
Comment
Question by:Remulac
  • 2
3 Comments
 
LVL 22

Expert Comment

by:_TAD_
ID: 13819322

XML commenting really should only be used just before each class/function/property declaration.

Commenting code within a funciton using XML commenting is overkill.  The point to using XML commenting is so that when you program with intellisense, you can see descriptions of the class or function from within VS.net.

0
 

Author Comment

by:Remulac
ID: 13819367
So you comment properties as well?  I guess the functions can be described with <summary>, <returns> and <param>, but what tag would you use for properties?  
0
 
LVL 22

Accepted Solution

by:
_TAD_ earned 1000 total points
ID: 13819452

the <summary> tag can be used for everything.  If you are using VS.Net, just type the threee slashes /// and it will prefill all of that data for you automatically.

It's a bit overkill... but here is some recent code I developed (encryption class).  It is fully documented with both standard comments and XML comments.  To sum up, use XML comments to describe all PUBLIC entities (functions, properties, delegates, etc).  As for private entities... XML is overkill, but if you want to maintain consitancy, it's not a bad choice.


<-------------SAMPLE------------->


using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Xml.Serialization;
using System.Security.Permissions;
using System.Security.Cryptography;
using System.Runtime.InteropServices;

[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)]
namespace BasicCryptography
{
   #region --Class HashingCipher--
   /// <summary>
   /// Uses an advanced hashing algorithm to encrypt data.
   /// This type of cipher is best used for one way encryption/hashing of data
   /// that is only suppose to be validated against, not decrypted.  
   /// </summary>
   [ComVisible(false)]
   public class HashingCipher: IDisposable
   {
      #region --Delegates--
      private delegate string PropertyValue();
      #endregion

      #region --Variables--
      private string text = string.Empty;
      private bool disposed;
      #endregion

      #region --Constructor/Destructor--
      /// <summary>
      /// Create one-way hashing instance
      /// </summary>
      public HashingCipher(){}

      /// <summary>
      /// deconstruct this class
      /// </summary>
      ~HashingCipher()
      {
         this.Dispose(false);
      }
      #endregion

      #region --Properties--
      /// <summary>
      /// Gets or Sets the text that was or will be encrypted
      /// </summary>
      public string Text
      {
         get{return this.text;}
         set{this.text = value;}
      }
     
     
      /// <summary>
      /// Clear/Encrypted Text in XML Format
      /// </summary>
      public string XmlText
      {
         get
         {
            PropertyValue myXml = new PropertyValue(SerializeToXml);
            return myXml();
         }
      }
      #endregion

      #region --Public Methods--
      /// <summary>
      /// Encrypt data using one way hashing method
      /// </summary>
      /// <param name="data">text value to be hashed</param>
      /// <returns>hashed/encrypted value</returns>
      public virtual void HashData(string asciiText)
      {
         // Convert string to byte[]
         byte[] buff = ASCIIEncoding.ASCII.GetBytes(asciiText);
         
         // Encrypt byte[] and convert to text
         this.text = Convert.ToBase64String(new SHA1Managed().ComputeHash(buff,0,buff.Length));
      }

      /// <summary>
      /// Disposes of object
      /// </summary>
      public void Dispose()
      {
         this.Dispose(true);
      }
      #endregion

      #region --Private Methods--
      /// <summary>
      /// Disposes of object
      /// </summary>
      /// <param name="disposing">Currently Disposing</param>
      private void Dispose(bool disposing)
      {
         if (!disposed)
         {
            // Dispose of resources held by this instance.
            if (this.text != null)
               this.text = string.Empty;

            // Set the sentinel.
            disposed = true;
   
            // Suppress finalization of this disposed instance.
            if (disposing)
            {
               GC.SuppressFinalize(this);
            }
         }
      }
      #endregion      

      #region --Public Functions--
      /// <summary>
      /// Returns the instance of ToString(); No actual conversion is performed.
      /// </summary>
      /// <returns>Current value of Text Property</returns>
      public override string ToString()
      {
         return this.Text;
      }
      #endregion
   
      #region --Private Functions--
      /// <summary>
      /// Delegated Function; Creates XML String
      /// </summary>
      /// <returns>ASCII Text of Clear/Encrypted data in XML format</returns>
      private string SerializeToXml()
      {
         // Create XML objects
         XmlSerializer ser;
         XmlDocument xmlDoc;
         XmlElement element;

         // Create and initialize streams
         MemoryStream ms = new MemoryStream();
         StreamWriter sw = new StreamWriter(ms);

         // Create and initialize return string
         string xml = string.Empty;

         try
         {
            // Create new xml document
            ser = new XmlSerializer(typeof(XmlDocument));
            xmlDoc = new XmlDocument();

            // Create and load elements with data
            element = xmlDoc.CreateElement("Text");
            element.InnerText = this.Text;

            // Add elements to document
            xmlDoc.AppendChild(element);
           
            // Serialize xml docmuent into a stream
            ser.Serialize(sw,xmlDoc);

            // Flush the stream
            sw.Flush();
            ms.Flush();

            // Write stream out to return string
            xml = Encoding.ASCII.GetString(ms.ToArray(),0,(int)ms.Length);
         }
         finally
         {
            // Finalize Streams
            ms.Close();
            sw.Close();
         }

         // return string
         return xml;
      }
      #endregion  

   }
   #endregion

   #region --Class RijndaelCipher--
   /// <summary>
   /// Uses the Rijndael symmetric encryption process to encrypt and decrypt data.
   /// This type of cipher is best used for data that needs to be encrypted and decrypted.
   /// </summary>
   [ComVisible(false)]
   public class RijndaelCipher: IDisposable
   {
      #region --Delegates--
      private delegate void Cipher(string text, ICryptoTransform transform);
      private delegate string PropertyValue();
      #endregion

      #region --Variables--
      private const int KEY_LENGTH = 32;
      private const int IV_LENGTH = 16;

      private RijndaelManaged myRijn;
      private MemoryStream ms;
      private CryptoStream cs;
      private StreamWriter sw;
      private StreamReader sr;
      private string key;
      private string iv;
      private string text;
      private bool disposed;
      #endregion
            
      #region --Constructor/Destructor--
      /// <summary>
      /// RijndaelCipher Class Constructor
      /// </summary>
      public RijndaelCipher()
      {
         myRijn = new RijndaelManaged();
      }

      /// <summary>
      /// Deconstruct RijndaelCipher class
      /// </summary>
      ~RijndaelCipher()
      {
         this.Dispose(false);
      }

      #endregion

      #region --Properties--
      /// <summary>
      /// Rijndael Key
      /// </summary>
      public string Key
      {
         get{return this.key;}
         set
         {
            if(Convert.FromBase64String(value).Length == KEY_LENGTH)
               this.key = value;
            else
               this.key = string.Empty;
         }
      }

     
      /// <summary>
      /// Rijndael Vector
      /// </summary>
      public string IV
      {
         get{return this.iv;}
         set
         {
            if(Convert.FromBase64String(value).Length == IV_LENGTH)
               this.iv = value;
            else
               this.iv = string.Empty;
         }
      }

     
      /// <summary>
      /// Clear/Encrypted Text
      /// </summary>
      public string Text
      {
         get{return this.text;}
         set{this.text = value;}
      }


      /// <summary>
      /// Clear/Encrypted Text in XML Format
      /// </summary>
      public string XmlText
      {
         get
         {
            PropertyValue myXml = new PropertyValue(SerializeToXml);
            return myXml();
         }
      }

      #endregion

      #region --Public Methods--
      /// <summary>
      /// Encrypts Text - Encrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be encrypted</param>
      /// <remarks>Key and Vector will be randomly generated</remarks>
      public virtual void EncryptText(string text)
      {
         // Randomly generate key and vector
         myRijn.GenerateKey();
         myRijn.GenerateIV();
         
         // Convert key and vector to string values
         this.Key = Convert.ToBase64String(myRijn.Key, 0, myRijn.Key.Length);
         this.IV = Convert.ToBase64String(myRijn.IV, 0, myRijn.IV.Length);

         // Isomorphic method call
         this.EncryptText(text, myRijn.Key, myRijn.IV);
      }      
     
     
      /// <summary>
      /// Encrypts Text - Encrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be encrypted - Encrypted text stored in Text Property</param>
      /// <param name="key">key/salt - 32 bytes</param>
      /// <param name="iv">vector - 16 bytes</param>
      public virtual void EncryptText(string text, byte[] key, byte[] iv)
      {
         // Isomorphic method call
         this.EncryptText(text, myRijn.CreateEncryptor(key, iv));
      }
     

      /// <summary>
      /// Encrypts Text - Encrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be encrypted - Encrypted text stored in Text Property</param>
      /// <param name="transform">ICryptoTransform which stores the key/vector combination</param>
      public virtual void EncryptText(string text, ICryptoTransform transform)
      {
         // Initialize and execute delegate
         Cipher encrypt = new Cipher(this.Encrypt);
         encrypt(text, transform);
      }

     
      /// <summary>
      /// Decrypts Text - Decrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be decrypted</param>
      /// <param name="key">Key used for decryption</param>
      /// <param name="iv">Vector used for decryption</param>
      public virtual void DecryptText(string text, byte[] key, byte[] iv)
      {
         // Isomorphic method call
         this.DecryptText(text, myRijn.CreateDecryptor(key, iv));
      }
     
     
      /// <summary>
      /// Decrypts Text - Decrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be decrypted</param>
      /// <param name="key">Key used for decryption</param>
      /// <param name="iv">Vector used for decryption</param>
      public virtual void DecryptText(string text, string key, string iv)
      {
         // Isomorphic method call
         this.DecryptText(text, Convert.FromBase64String(key), Convert.FromBase64String(iv));
      }

     
      /// <summary>
      /// Decrypts Text - Decrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be decrypted</param>
      /// <param name="transform">ICryptoTransform that holds the key/vector combination</param>
      public virtual void DecryptText(string text, ICryptoTransform transform)
      {
         // Initialize and Execute delegate
         Cipher decrypt = new Cipher(this.Decrypt);
         decrypt(text, transform);
      }

     
      /// <summary>
      /// Disposes of object
      /// </summary>
      public void Dispose()
      {
         this.Dispose(true);
      }
      #endregion
     
      #region --Private Methods--
      /// <summary>
      /// Delegated Function; Encrypts Text - Encrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be encrypted - Encrypted text stored in Text Property</param>
      /// <param name="transform">ICryptoTransform which stores the key/vector combination</param>
      private void Encrypt(string text, ICryptoTransform transform)
      {        
         // Create new streams
         ms = new MemoryStream();
         cs = new CryptoStream(ms, transform,CryptoStreamMode.Write);
         sw = new StreamWriter(cs);
         
         // Write streams out (encrypts text)
         sw.Write(text);
         sw.Flush();
         cs.FlushFinalBlock();
         ms.Flush();

         // Returns ASCII value of Encrypted Text
         this.Text = Convert.ToBase64String(ms.GetBuffer(),0,(int)ms.Length);

         // Finalize Streams
         sw.Close();
         cs.Clear();
         cs.Close();
         ms.Close();
      }


      /// <summary>
      /// Delegated Function; Decrypts Text - Decrypted text stored in Text Property
      /// </summary>
      /// <param name="text">Text to be decrypted</param>
      /// <param name="transform">ICryptoTransform that holds the key/vector combination</param>
      private void Decrypt(string text, ICryptoTransform transform)
      {
         // Convert encrypted text to a byte[]
         byte[] buff = Convert.FromBase64String(text);
         
         // Create new streams
         ms = new MemoryStream(buff);
         cs = new CryptoStream(ms, transform, CryptoStreamMode.Read);
         sr = new StreamReader(cs);
         
         // Write stream out to text property
         this.Text = sr.ReadToEnd();

         // Finalize streams
         sr.Close();
         cs.Clear();
         cs.Close();
         ms.Close();

         buff = null;
      }

      /// <summary>
      /// Disposes of object
      /// </summary>
      /// <param name="disposing">Currently Disposing</param>
      private void Dispose(bool disposing)
      {
         if (!disposed)
         {
            #region -Finalize Class Level Objects-
            // Dispose of resources held by this instance.
            if (this.myRijn != null)
               this.myRijn.Clear();
           
            if (this.sw != null)
               this.sw.Close();

            if (this.sr != null)
               this.sr.Close();
           
            if (this.cs != null)
            {
               this.cs.Clear();
               this.cs.Close();
            }
           
            if (this.ms != null)
               this.ms.Close();

            if (this.key != null)
               this.key = string.Empty;

            if (this.iv != null)
               this.iv = string.Empty;

            if (this.text != null)
               this.text = string.Empty;
            #endregion

            // Set the sentinel.
            this.disposed = true;
   
            // Suppress finalization of this disposed instance.
            if (disposing)
            {
               GC.SuppressFinalize(this);
            }
         }
      }
      #endregion

      #region --Public Functions--
      /// <summary>
      /// Returns the instance of ToString(); No actual conversion is performed.
      /// </summary>
      /// <returns>Current value of Text Property</returns>
      public override string ToString()
      {
         return this.Text;
      }
      #endregion

      #region --Private Functions--
      /// <summary>
      /// Delegated Function; Creates XML String
      /// </summary>
      /// <returns>ASCII Text of Clear/Encrypted data in XML format</returns>
      private string SerializeToXml()
      {
         // Create XML objects
         XmlSerializer ser;
         XmlDocument xmlDoc;
         XmlElement element;

         // Create and initialize streams
         MemoryStream ms = new MemoryStream();
         StreamWriter sw = new StreamWriter(ms);

         // Create and initialize return string
         string xml = string.Empty;

         try
         {
            // Create new xml document
            ser = new XmlSerializer(typeof(XmlDocument));
            xmlDoc = new XmlDocument();

            // Create and load elements with data
            element = xmlDoc.CreateElement("Text");
            element.SetAttribute("Key",this.Key);
            element.SetAttribute("Vector",this.IV);
            element.InnerText = this.Text;

            // Add elements to document
            xmlDoc.AppendChild(element);
           
            // Serialize xml docmuent into a stream
            ser.Serialize(sw,xmlDoc);

            // Flush the stream
            sw.Flush();
            ms.Flush();

            // Write stream out to return string
            xml = Encoding.ASCII.GetString(ms.ToArray(),0,(int)ms.Length);
         }
         finally
         {
            // Finalize Streams
            ms.Close();
            sw.Close();
         }

         // return string
         return xml;
      }
      #endregion
   }
   #endregion
}

0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my previous article (http://www.experts-exchange.com/Programming/Languages/.NET/.NET_Framework_3.x/A_4362-Serialization-in-NET-1.html) we saw the basics of serialization and how types/objects can be serialized to Binary format. In this blog we wi…
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
This Micro Tutorial will teach you how to add a cinematic look to any film or video out there. There are very few simple steps that you will follow to do so. This will be demonstrated using Adobe Premiere Pro CS6.
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses
Course of the Month19 days, 20 hours left to enroll

873 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question