Tech Off Thread

12 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

C# Best Practice Question

Back to Forum: Tech Off
  • User profile image
    Deactivated User

    Comment removed at user's request.

  • User profile image
    GooberDLX

    GOOD question...

    I only use Option #1 because thats what Java taught me.. It makes sense in that its not direct code involved within the framework, but at the same time, with option #2, you are saying that your namespace is using other namespaces..

    I want to hear more on other peoples thoughts...

    Jake

  • User profile image
    spod

    Internally we use option 2. I seem to remember there being a good rationale for making that decision when we did, but it escapes me now Smiley

    I'll ask around and see if i can come up with any justification for it...

  • User profile image
    irascian

    We switched to using Option 2 after a situation where a namespace that was being referenced wasn't working.
    Actually we use option 1 for System. references and option 2 for our own dll references.

    I wasn't directly involved but I remember our lead developer expressing astonishment that you could even do option 2 and that it got around the problem one of our developers was experiencing.

    I'll try and find out more on Monday. 

  • User profile image
    Deactivated User

    Comment removed at user's request.

  • User profile image
    slynch

    The way I had thought that the using directive worked was essentially saying, if you dont find it in the current namespace look in these name spaces for it. Or in the case of using Data = System.Data is a way to shorten the name space. 
     
    Also looking at the IL there really are no using, all the types have fully qualified namespaces.

    So I would think that it is a matter of preference.

  • User profile image
    Pseudo

    i've always done the first one, but i wondered about doing it the other way.

    i never tried it, but I assume they can go anywhere in the file.

  • User profile image
    stevem

    irascian wrote:

    We switched to using Option 2 after a situation where a namespace that was being referenced wasn't working.
    Actually we use option 1 for System. references and option 2 for our own dll references.


    It turns out that there's a small semantic difference between the two. This can cause problems when you have a class with the same name as it's enclosing namespace (this is, in general, a really bad practice because it just confuses everyone. But it does happen).

    As an example, consider this class:

    namespace NamespaceMangler
    {
      public class NamespaceMangler
      {
        public static void Mangle(){}
      }
    }


    Things get confusing when the static Mangle() member needs to be called from types that exist in another namespace. One way to get this code to compile is to use Option 2 without a namespace-qualified type, like so:

    //If you put the using statment out here, you'll get
    //a compiler error.
    namespace AnotherNamespace
    {
      //Putting it here works, though...
      using NamespaceMangler;

      public class AnotherClass
      {
        public AnotherClass()
        {
           NamespaceMangler.Mangle();
        }
      }
    }

    If you were to use Option 1 and put the using outside of the namespace delcaration, you'd get a compiler error complaining that that NamespaceMangler does not declare a type called Mangle. The poor compiler has become confused, thinking that you meant NamespaceMangler-the-namespace instead of NamespaceMangler-the-type.

    Interestingly enough, if you use Option 2 but attempt to clairfy things by namespace-qualifying the type name, you'll get a compiler error. For example, this code will not compile:

    namespace AnotherNamespace
    {
      using NamespaceMangler;

      public class AnotherClass
      {
        public AnotherClass()
        {
           NamespaceMangler.NamespaceMangler.Mangle();
        }
      }
    }

    This problem is particularly annoying because it's exactly how the CSharpCodeGenerator likes to format its output. Thus, if you're generating code via CodeDom and have accidentally created a type with the same name as it's enclosing namespace, the generated code will be unable to compile! Grr.

    The part of the C# spec that governs this behavior is Section 10.8, paragraph 4. Apparently, it's confusing enough to motivate the return of the global namespace resolution operator for C# 2.0, a.k.a. the "double snakebite" operator (:Smiley. Prefixing a type name with :: will ensure that namespace resolution begins at the global namespace, thereby avoiding this whole bloody mess entirely.

    The bottom line: don't create types with the same name as their enclosing namespace!

    -steve
    http://hyperthink.net/blog

  • User profile image
    clint_hill

    stevem wrote:


    This problem is particularly annoying because it's exactly how the CSharpCodeGenerator likes to format its output. Thus, if you're generating code via CodeDom and have accidentally created a type with the same name as it's enclosing namespace, the generated code will be unable to compile! Grr.



    Day late and dollar short to be the hero on this one, but to back up stevem here is a little bit of code I use to create "template" files. I have an exe that uses this class to create .cs files for me. Saves me the typing and gets right to the code. <note>First time posting code, forgive me if it comes off formatted poorly</note>

    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using Microsoft.CSharp;
    namespace CodeGenerator
    {
    /// <summary>
    /// Summary description for DOM.
    /// </summary>
    public class DOM
    {
    private string fileName;
    private CodeCompileUnit codeCompileUnit;
    private CodeNamespace codeNamespace;
    private CodeDomProvider codeDomProvider;
    private ICodeGenerator generator;
    public DOM()
    {
    codeCompileUnit = new CodeCompileUnit();
    codeNamespace = new CodeNamespace();
    codeNamespace.Name = "DefaultNamespace";
    }
    public string Namespace
    {
    get { return this.codeNamespace.Name; }
    set { this.codeNamespace.Name = value;}
    }
     
    public string FileName
    {
    get { return this.fileName; }
    set { this.fileName = value; }
    }
    public void AddUsingStatement(string import)
    {
    CodeNamespaceImport newImport = new CodeNamespaceImport(import);
    this.codeNamespace.Imports.Add(newImport);
    }
    public void AddType(string type)
    {
    CodeTypeDeclaration newType = new CodeTypeDeclaration(type);
    this.codeNamespace.Types.Add(newType);
    CodeConstructor constructor = new CodeConstructor();
    constructor.Name = type;
    constructor.Attributes = MemberAttributes.Public;
    this.codeNamespace.Types[0].Members.Add(constructor);
    }
     
    public void AddMember(string type, string name)
    {
    CodeMemberField codeMemberField = new CodeMemberField(type,name.ToLower());
    this.codeNamespace.Types[0].Members.Add(codeMemberField);
    CodeMemberProperty codeMemberProperty = new CodeMemberProperty();
    codeMemberProperty.Name = name;
    codeMemberProperty.Type = new CodeTypeReference(type);
    codeMemberProperty.Attributes = MemberAttributes.Public;
    codeMemberProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),name.ToLower())));
    codeMemberProperty.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),name.ToLower()),new CodePropertySetValueReferenceExpression()));
    this.codeNamespace.Types[0].Members.Add(codeMemberProperty);
    }
    public void GenerateFile()
    {
    codeDomProvider = new CSharpCodeProvider();
    generator = codeDomProvider.CreateGenerator(this.fileName);
     
    codeCompileUnit.Namespaces.Add(codeNamespace);
    System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(this.fileName,false);
    CodeGeneratorOptions generatorOptions = new CodeGeneratorOptions();
    generatorOptions.BracingStyle = "C";
    generator.GenerateCodeFromCompileUnit(this.codeCompileUnit,streamWriter,generatorOptions);
    streamWriter.Close();
    }
    }
    }

  • User profile image
    kozlow

    stevem wrote:

    The bottom line: don't create types with the same name as their enclosing namespace!



    Does somebody can inform the TabletPC team of this rule !!?

    The Ink class in Microsoft.Ink namespace is really annoying :<

    Change its name for longhorn !

    Mat

  • User profile image
    samunro

    And what's the story with System.Data and System.CodeDom? Why do so many classes have the same prefix? eg. DataReader, DataTable, DataRow, DataColumn, etc or CodeNameSpace, CodeClass, CodeMember, CodeFunction etc?

    Isn't it the job of the namespace to group classes logically?

  • User profile image
    Deactivated User

    Comment removed at user's request.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.