Skip to content

Document describing pitfalls and bugs in the C# language, compiler or .NET framework

License

Notifications You must be signed in to change notification settings

bdb-opensource/c-sharp-pitfalls

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 

Repository files navigation

Contributing: Either open an issue on the github page, or fork and send a pull request.

C#/.NET Pitfalls

C# Language & Compiler

Pitfalls

  1. Calls to GetType() on a Nullable<T> instance always return T, although the type is Nullable<T>.

  2. Co/contravariance does not work on value types (i.e. in interface ITest<out T>, if it is used with a T that's a value type the out keyword has no effect).

  3. Type constraints are ignored when resolving method overloads. Calls to a method that has overrides where only one matches the current type constraints, are still considered ambiguous.

  4. Array types T[] implement ICollection<T> and other incompatible interfaces. Arrays of T (T[]) "implement" some intefaces such as ICollection<T>, but don't really implement them. Instead, the throw NotImplementedException on methods they can't implement (such as Add).

  5. Arrays are covariant despite being writable. In other words: you can assign object[] x = new string[1]. If you then go ahead and do x[0] = new Something(); you get an exception. Furthermore, as Jon Skeet explains, array covariance is not just ugly, but slow too.

  6. You can't combine getter and setter properties via interface inheritance. The compiler sees an ambiguity when trying to access a property "MyProp" when inheriting a setter from one interface, and the same property's getter from another interface. Properties are not like a pair of methods.

     interface IGet { int Value { get; } }
     
     interface ISet { int Value { set; } }
     
     interface IBoth : IGet, ISet { }
     
     class Test
     {
         public void Bla(IBoth a)
         {
             var x = a.Value; // Error: Ambiguity between 'IGet.Value' and 'ISet.Value'
         }
     }
    

    According to Eric Lippert the reason is to simplify the compiler's implementation.

  7. Comparing a class to an interface with == always compiles, even if they are unrelated. Consider two unrelated classes A and B and variables a and b of corresponding types. Using ==, you can't compare a == b (fails compilation) - this is expected. Now consider an unrelated interface IC and variable c - you can compare a == c despite those types not matching. The reason is that there might be a class D : A, IC for which the comparison will make sense. This should be at least a warning (apparently it is in VS >= 2012).

  8. Default parameters are compile-time substitutions, so if you change a parameter's default value without recompiling dependencies, they will still use the old value.

You may forget this

  1. Struct members cannot be protected (because structs cannot be inherited.)

Bugs

  1. When comparing (using ==) a nullable to a non-nullable generic struct in an expression, you get a runtime error. The Connect issue explains that the bug is fixed in Roslyn, but will probably not be fixed in the current (old) compiler.
  2. As explained in pitfalls above, co/contravariance does not work for value-type type parameters. However, the compiler will allow you to constrain a type parameter to be a value (struct) resulting in a useless co/contravariance declaration.

.NET

  1. The DateTime.Equals method ignores .Kind, which makes the Equals method an unreliable of comparing DateTimes. As discussed in this SO question, the moral is not to use it at all.

Working with SQL (including Linq to SQL / Entity Framework)

  1. Bug (fixed in EF6): A LINQ query such as where entity.str == myString when myString is null, will always return false - even if 'str' is a nullable column. (http://stackoverflow.com/questions/8090894/linq-to-entities-and-null-strings) This is because in SQL, [Column] = null always evaluates to false (to check for nulls you need [Column] is null).
  2. DateTime loss of milliseconds resolution: The sql server type datetime has less resolution than the .NET DateTime type. This means that if you save a DateTime value it won't be the same value when you read it back. EF is aware of this if you use '2005' for the SqlProvider manifest token which can be a bit tricky to do in Code First.

WCF

  1. If a method parameter is not passed when calling a WCF service method, that parameter is initialized to some default value http://thorarin.net/blog/post/2010/08/08/Controlling-WSDL-minOccurs-with-WCF.aspx

  2. Linq-to-SQL: Non-collection references between two entities (e.g. Division -> DivisionDeduction), is not serialized (no DataMember attribute is created on either side)

  3. WCF service hosted in IIS: When defining custom error pages for some error codes, IIS will mask WCF exceptions and send the custom error page itself (despite this being a service).

About

Document describing pitfalls and bugs in the C# language, compiler or .NET framework

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published