I am an experienced C++ developer, I know the language in great details and have used some of its specific features intensively. Also, I know principles of OOD and design patterns. I am now learning C# but I cannot stop the feeling not being able to get rid of C++ mindset. I tied myself so hard to the strengths of C++ that I cannot live without some of the features. And I cannot find any good workarounds or replacements for them in C#.
What good practices, design patterns, idioms that are different in C# from C++ perspective can you suggest? How to get a perfect C++ design not looking dumb in C#?
Specifically, I cannot find a good C#-ish way to deal with (recent examples):
- Controlling the lifetime of resources that require deterministic cleanup (like files). This is easy having
using
in hand but how to use it properly when ownership of the resource is being transfered [… betwen threads]? In C++ I would simply use shared pointers and let it take care of ‘garbage collection’ just at the right time. - Constant struggling with overriding functions for specific generics (I love things like partial template specialization in C++). Should I just abandon any attempts to do any generic programming in C#? Maybe generics are limited on purpose and it is not C#-ish to use them except for a specific domain of problems?
- Macro-like functionality. While generally a bad idea, for some domain of problems there is no other workaround (e.g. conditional evaluation of a statement, like with logs that should only go to Debug releases). Not having them means that I need to put more
if (condition) {...}
boilerplate and it is still not equal in terms of triggering side effects.
4
In my experience, there is no book to do this. Forums help with idioms and best practices, but in the end you’re going to have to put in the time. Practice by solving a number of different problems in C#. Look at what was hard/awkward and try to make them less hard and less awkward next time. For me, this process took about a month before I “got it”.
The biggest thing to focus on is the lack of memory management. In C++ this lords over every single design decision you make, but in C# it is counter productive. In C#, you often want to ignore the death or other state transitions of your objects. That sort of association adds unnecessary coupling.
Mostly, focus on using the new tools most effectively, not beating yourself up over an attachment to the old ones.
How to get a perfect C++ design not looking dumb in C#?
By realizing that different idioms push towards different design approaches. You can’t just port something 1:1 between (most) languages and expect something beautiful and idiomatic on the other end.
But in response to specific scenarios:
Shared unmanaged resources – This was a bad idea in C++, and is just as much a bad idea in C#. If you have a file then open it, use it, and close it. Sharing it between threads is just asking for trouble, and if only one thread is really using it then have that thread open/own/close it. If you really have a long lived file for some reason, then make a class to represent that and let the application manage that as needed (close before exit, tie close to Application Closing sort of events, etc)
Partial Template Specialization – You’re out of luck here, though the more I’ve used C# the more I find the template usage I did in C++ to fall into YAGNI. Why make something generic when T is always an int? Other scenarios are best solved in C# by liberal application of interfaces. You don’t need generics when an interface or delegate type can strongly type what you want to vary.
Preprocessor conditionals – C# has #if
, go nuts. Better yet, it has conditional attributes that will simply drop that function from the code if a compiler symbol is not defined.
4
As far as I can see, the only thing allowing for deterministic Lifetime Management is IDisposable
, which breaks down (as in: no language or type system support) when, as you noticed, you need to Transfer Ownership of such a resource.
Being in the same boat as you — C++ developer doing C# atm. — the lack of support to model Ownership Transfer (files, db-connections, …) in the C# types/signatures has been very annoying to me, but I have to admit that it does work quite OK to “just” rely on convention and API docs to get this right.
- Use
IDisposable
to do deterministic clean up iff necessary. - When you need to transfer ownership of an
IDisposable
, just make sure the API involved is clear on this and don’t useusing
in this case, becauseusing
can’t be “cancelled” so to speak.
Yes, it’s not as elegant as what you can express in the type system with modern C++ (move sematics, etc.), but it get’s the job done, and (amazingly to me) the C# community as a whole doesn’t seem to care overmuch, AFAICT.
You mentioned two specific C++ features. I’ll discuss RAII:
It is usually not applicable, since C# is garbage collected. The closest C# construction is probably the IDisposable
interface, used as follows:
using (FileStream fs = File.OpenRead(@"c:pathfilename.txt"))
{
//Do stuff with the file.
} //File will be closed here.
You shouldn’t expect to implement IDisposable
often (and doing so is slightly advanced), as it’s not necessary for managed resources. However, you should use the using
construct (or call Dispose
yourself, if using
is infeasible) for anything implementing IDisposable
. Even if you mess this up, well-designed C# classes will try to handle this for you (using finalizers). However, in a garbage-collected language the RAII pattern doesn’t fully work (since collection is non-deterministic), so your resource cleanup will be delayed (sometimes catastrophically).
8
This is a very good question, as I have seen a number of C++ developers write terrible C# code.
It is best not to think of C# as “C++ with nicer syntax”. They are different languages which require different approaches in your thinking. C++ forces you to be constantly thinking about what the CPU and memory will be doing. C# is not like that. C# specifically is designed so that you are not thinking about the CPU and memory and instead are thinking about the business domain you are writing for.
One example of this that I have seen is that a lot of C++ developers will like to use for loops because they’re faster than foreach. This is usually a bad idea in C# because it restricts the possible types of the collection being iterated over (and therefore the re-usability and flexibility of the code).
I think that the best way to readjust from C++ to C# is to try and approach coding from a different perspective. At first this will be hard, because over the years you will be completely used to using the “what are the CPU and memory doing” thread in your brain to filter the code you write. But in C#, you should instead be thinking about the relationships between the objects in the business domain. “What do I want to do” as opposed to “what is the computer doing”.
If you want to do something to everything in a list of objects, instead of writing a for loop on the list, create a method which takes an IEnumerable<MyObject>
and use a foreach
loop.
Your specific examples:
Controlling the lifetime of resources that require deterministic cleanup (like files). This is easy having using in hand but how to use it properly when ownership of the resource is being transfered [… betwen threads]? In C++ I would simply use shared pointers and let it take care of ‘garbage collection’ just at the right time.
You should never do this in C# (particularly between threads). If you need to do something to a file, do it in one place at one time. It’s ok (and indeed good practice) to write a wrapper class which manages the unmanaged resource which gets passed between your classes, but don’t try and pass a File between threads and have separate classes write/read/close/open it. Don’t share ownership of unmanaged resources. Use the Dispose
pattern to deal with cleanup.
Constant struggling with overriding functions for specific generics (I love things like partial template specialization in C++). Should I just abandon any attempts to do any generic programming in C#? Maybe generics are limited on purpose and it is not C#-ish to use them except for a specific domain of problems?
Generics in C# are designed to be generic. Specializations of generics should be handled by derived classes. Why should a List<T>
behave differently if it’s a List<int>
or a List<string>
? All of the operations on List<T>
are generic so as to apply to any List<T>
. If you want to change the behaviour of the .Add
method on a List<string>
, then create a derived class MySpecializedStringCollection : List<string>
or a composed class MySpecializedStringCollection : IList<string>
which uses the generic internally but does things in the different way. This helps you avoid violating the Liskov Substitution Principle and royally screwing others who use your class.
Macro-like functionality. While generally a bad idea, for some domain of problems there is no other workaround (e.g. conditional evaluation of a statement, like with logs that should only go to Debug releases). Not having them means that I need to put more if (condition) {…} boilerplate and it is still not equal in terms of triggering side effects.
As others have said, you can use preprocessor commands to do this. Attributes are even better. In general attributes are the best way to handle things which are not “core” functionality for a class.
In short, when writing C#, keep in mind that you should be thinking entirely about the business domain and not about the CPU and memory. You can optimize later if necessary, but your code should reflect the relationships between the business principles you’re trying to map.
2
The thing that was most different for me was the tendency to new everything. If you want a object, forget trying to pass it to a routine and share the underlying data, it seems the C# pattern is just to create yourself a new object. This, in general, seems to be much more of the C# way. At first this pattern seemed very inefficient, but I guess creating most objects in C# is a quick operation.
However, there’s also the static classes that really annoy me as every so often you try to create one only to find you have to just use it. I find its not so easy to know which to use.
I’m quite happy in a C# program to just ignore it when I no longer need it, but just remember what that object contains – generally you only have to think if it has some ‘unusual’ data, objects that only consist of memory will just go away by themselves, others will have to be disposed or you’ll have to look at how to destroy them – manually or by a using block if not.
you’ll very quickly pick it up though, C# is hardly any different from VB so you can treat it as the same RAD tool it is (if it helps to think of C# like VB.NET then do so, the syntax is only slightly different, and my old days of using VB got me into the right mindset for RAD development). The only difficult bit is determining what bit of the huge .net libraries you should use. Google is most definitely your friend here!
1