What is the worst gotcha in C# or .NET?
private int myVar;
public int MyVar
{
get { return MyVar; }
}
Blammo. Your app crashes with no stack trace. Happens all the time.
(Notice capital MyVar
instead of lowercase myVar
in the getter.)
What's the strangest corner case you've seen in C# or .NET?
I think I showed you this one before, but I like the fun here - this took some debugging to track down! (the original code was obviously more complex and subtle...)
static void Foo<T>() where T : new()
{
T t = new T();
Console.WriteLine(t.ToString()); // works fine
Console.WriteLine(t.GetHashCode()); // works fine
Console.WriteLine(t.Equals(t)); // works fine
// so it looks like an object and smells like an object...
// but this throws a NullReferenceException...
Console.WriteLine(t.GetType());
}
So what was T...
Answer: any Nullable<T>
- such as int?
. All the methods are overridden, except GetType() which can't be; so it is cast (boxed) to object (and hence to null) to call object.GetType()... which calls on null ;-p
Update: the plot thickens... Ayende Rahien threw down a similar challenge on his blog, but with a where T : class, new()
:
private static void Main() {
CanThisHappen<MyFunnyType>();
}
public static void CanThisHappen<T>() where T : class, new() {
var instance = new T(); // new() on a ref-type; should be non-null, then
Debug.Assert(instance != null, "How did we break the CLR?");
}
But it can be defeated! Using the same indirection used by things like remoting; warning - the following is pure evil:
class MyFunnyProxyAttribute : ProxyAttribute {
public override MarshalByRefObject CreateInstance(Type serverType) {
return null;
}
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }
With this in place, the new()
call is redirected to the proxy (MyFunnyProxyAttribute
), which returns null
. Now go and wash your eyes!
What is the advantage of Path.TryJoin over Path.Combine in .NET Core?
You can find the rationale behind the Path.Join
being introduced here. IMHO it seems to be trading simplicity for performance and some minor fixes, also couldn't find any indication that Join creates cross-platform valid paths with the correct separators like Path.Combine
does but by all accounts is should.
To elaborate on the discussion, the main quirk that Path.Join
resolves is the last rooted argument which a lot of people don't expect to work the way it does (which seamed minor but clearly is not), as can be seen in the examples here on the the worst gotcha in C# or .NET page.
The general idea from the discussion is to slowly deprecate Combine
in favor of Join
.
Also note string overloads have been added for the Path.Join
with this PR
C# (.NET) Design Flaws
I agree emphatically with this post (for those poo-pooing the lack of ToString, there is a debugger attribute to provide a custom format for your class).
On top of the above list, I would also add the following reasonable requests:
- non-nullable reference types as a complement to nullable value types,
- allow overriding a struct's empty constructor,
- allow generic type constraints to specify sealed classes,
- I agree with another poster here that requested arbitrary constructor signatures when used as constraints, ie. where
T : new(string)
, or whereT : new(string, int)
- I also agree with another poster here about fixing events, both for empty event lists and in the concurrent setting (though the latter is tricky),
- operators should be defined as extension methods, and not as static methods of the class (or not just as static methods at least),
- allow static properties and methods for interfaces (Java has this, but C# does not),
- allow event initialization in object initializers (only fields and properties are currently allowed),
- why is the "object initializer" syntax only usable when creating an object? Why not make it available at any time, ie.
var e = new Foo(); e { Bar = baz };
- fix quadratic enumerable behaviour,
- all collections should have immutable snapshots for iteration (ie. mutating the collection should not invalidate the iterator),
- tuples are easy to add, but an efficient closed algebraic type like "
Either<T>
" is not, so I'd love some way to declare a closed algebraic type and enforce exhaustive pattern matching on it (basically first-class support for the visitor pattern, but far more efficient); so just take enums, extend them with exhaustive pattern matching support, and don't allow invalid cases, - I'd love support for pattern matching in general, but at the very least for object type testing; I also kinda like the switch syntax proposed in another post here,
- I agree with another post that the
System.IO
classes, likeStream
, are somewhat poorly designed; any interface that requires some implementations to throwNotSupportedException
is a bad design, IList
should be much simpler than it is; in fact, this may be true for many of the concrete collection interfaces, likeICollection
,- too many methods throw exceptions, like IDictionary for instance,
- I would prefer a form of checked exceptions better than that available in Java (see the research on type and effect systems for how this can be done),
- fix various annoying corner cases in generic method overload resolution; for instance, try providing two overloaded extension methods, one that operates on reference types, and the other on nullable struct types, and see how your type inference likes that,
- provide a way to safely reflect on field and member names for interfaces like
INotifyPropertyChanged
, that take the field name as a string; you can do this by using an extension method that takes a lambda with aMemberExpression
, ie.() => Foo
, but that's not very efficient,- Update: C# 6.0 added the
nameof()
operator for single member names, but it doesn't work in generics (nameof(T) == "T"
instead of the actual type-argument's name: you still need to dotypeof(T).Name
)) - nor does it allow you to get a "path" string, e.g.nameof(this.ComplexProperty.Value) == "Value"
limiting its possible applications.
- Update: C# 6.0 added the
- allow operators in interfaces, and make all core number types implement
IArithmetic
; other useful shared operator interfaces are possible as well, - make it harder to mutate object fields/properties, or at the very least, allow annotating immutable fields and make the type checker enforce it (just treat it as getter-only property fer chrissakes, it's not hard!); in fact, unify fields and properties in a more sensible way since there's no point in having both; C# 3.0's automatic properties are a first step in this direction, but they don't go far enough,
- Update: While C# had the
readonly
keyword, and C# 6.0 added read-only auto-properties, though it isn't as stringent as true language support for immutable types and values.
- Update: While C# had the
- simplify declaring constructors; I like F#'s approach, but the other post here that requires simply "new" instead of the class name is better at least,
That's enough for now I suppose. These are all irritations I've run into in the past week. I could probably go on for hours if I really put my mind to it. C# 4.0 is already adding named, optional and default arguments, which I emphatically approve of.
Now for one unreasonable request:
- it'd be really, really nice if C#/CLR could support type constructor polymorphism, ie. generics over generics,
Pretty please? :-)
Making the most of the .NET Task Parallel Library
my gut feeling is that TPL is not suited to performing tasks where the data must appear in a particular order.
Correct. If you expect things in order, you might have a misunderstanding about what's going to happen when you "parallelize" a loop.
Does the TPL automatically make use of multicore architectures of must I provision anything prior to execution?
See the following article on the msdn magazine:
http://msdn.microsoft.com/en-us/magazine/cc163340.aspx
Using the library, you can conveniently express potential parallelism
in existing sequential code, where the exposed parallel tasks will be
run concurrently on all available processors.
Naming conventions for private members of .NET types
Technically, underscores are a violation of .NET conventions (or at least used to be -- see comment thread), but Microsoft programmers themselves often use underscores, and many examples in the documentation use underscores. I think it's very helpful to be able to see at a glance which variables are member variables (fields) and which are local. The underscore really helps with this. It also nicely separates private member variables from local variables in intellisense.
Please see this very useful page for .NET naming conventions:
http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices
And here's a page with Microsoft's official recommendations:
https://msdn.microsoft.com/en-us/library/ms229045%28v=vs.110%29.aspx
Related Topics
How to Seed in Entity Framework Core 2
How to Protect Resources That May Be Used in a Multi-Threaded or Async Environment
How to Post a List of Items in MVC
Restrict Access to a Specific Controller by Ip Address in ASP.NET MVC Beta
ASP.NET MVC: How to Redirect a Non Www to Www and Vice Versa
Async Void, ASP.NET, and Count of Outstanding Operations
Why Is Valuetype.Gethashcode() Implemented Like It Is
What Interfaces Do All Arrays Implement in C#
Static Generic Class as Dictionary
Retrieve Image from Database in ASP.NET
How to Get the Name of the Current Executable in C#
Using Case/Switch and Gettype to Determine the Object
How to Populate a Dropdownlist from a Database
Ef 4.1 - Code First - JSON Circular Reference Serialization Error