Skip to content

Latest commit

 

History

History
67 lines (40 loc) · 6.38 KB

README.md

File metadata and controls

67 lines (40 loc) · 6.38 KB

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).