12

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
  • #1 is a hard one for me, would like to know the answer myself. #2 - could you give a simple C++ code example and explain why you need that? For #3 - use C# to generate other code. You can read a CSV or an XML or what have you file as an input and generate a C# or an SQL file. This can be more powerful than using functional macros.
    – Job
    Commented Aug 16, 2013 at 4:36
  • On the topic of macro-like functionality, what specific things are you trying to do? What I've found is that there's usually a C# language construct to handle what I would have done with a macro in C++. Also check out the C# preprocessor directives: msdn.microsoft.com/en-us/library/4y6tbswk.aspx
    – ravibhagw
    Commented Feb 2, 2015 at 3:46
  • Many things done with macros in C++ can be done with reflection in C#. Commented Apr 28, 2015 at 8:27
  • It is one of my pet peeves when someone says "The right tool for the right job - choose a language based on what you're going to need." For large programs in general-purpose languages, this is a useless, unhelpful statement. That said, the thing that C++ is better at than almost any other language is deterministic resource management. Is deterministic resource management a primary feature of your program, or something you're used to? If it's not an important user feature, you may be overly focused on that.
    – Ben
    Commented Apr 28, 2015 at 13:30

5 Answers 5

16

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
  • Regarding resource management, in C# it is quite common to have manager classes (which can be static or dynamic).
    – rwong
    Commented Apr 28, 2015 at 7:51
  • Regarding shared resources: The managed ones are easy in C# (if race-conditions are irrelevant), the unmanaged ones are far nastier. Commented Apr 28, 2015 at 11:03
  • @rwong - common, but manager classes are still an anti-pattern to be avoided.
    – Telastyn
    Commented Apr 28, 2015 at 12:54
  • With regards to memory management, I found that switching to C# made this more difficult, especially in the beginning. I think you have to be more aware than in C++. In C++ you know exactly when and where every object is allocated, deallocated and referenced. In C#, this is all hidden from you. Many times in C# you don't even realize that a reference to an object has been obtained and memory starts leaking. Have fun tracking down memory leaks in C#, which are usually trivial to figure out in C++. Of course, with experience you learn these nuances of C# so they tend to become less of an issue.
    – Dunk
    Commented Apr 28, 2015 at 19:13
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 use using in this case, because using 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.

2

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:\path\filename.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
  • RAII is my biggest trouble indeed. Say I have a resource (say a file) that is created by one thread and given away to another. How can I make sure that it is disposed at a certain time when that thread does not need it anymore? Of course, I could call Dispose but then it looks way uglier than shared pointers in C++. There's nothing of RAII in it.
    – Andrew
    Commented Aug 14, 2013 at 21:19
  • @Andrew What you describe seem to imply transfer of ownership, so now the second thread is responsible for Disposing() the file and should probably use using.
    – svick
    Commented Aug 14, 2013 at 21:37
  • @Andrew - In general, you should not do that. You should instead tell the thread how to get the file and let it have ownership of the lifetime.
    – Telastyn
    Commented Aug 14, 2013 at 21:45
  • 1
    @Telastyn Does it mean that giving away ownership over a managed resource is a bigger problem in C# than in C++? Quite surprising.
    – Andrew
    Commented Aug 14, 2013 at 21:57
  • 6
    @Andrew: Let me summarize: in C++, you get uniform, semi-automatic management of all resources. In C#, you get completely automatic management of memory -- and completely manual management of everything else. There's no real changing it, so your only real question is not "how do I fix this?", only "how do I get used to this?" Commented Aug 16, 2013 at 1:07
2

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
  • 3
    WRT. resource transfer: "you should never do this" doesn't cut it IMHO. Often, a very good design suggests transfer of an IDisposable (not the raw resource) from one class to another: Just see the StreamWriter API where this makes perfect sense to Dispose() of the passed stream. And there lies the hole in the C# language - you cannot express this in the type system.
    – Martin Ba
    Commented Feb 3, 2015 at 9:08
  • 2
    "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 a bad idea in C++ too. Zero-cost abstraction is the great power of C++, and foreach or other algorithms shouldn't be slower than a hand-written for loop in most cases. Commented Apr 28, 2015 at 8:25
1

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
  • 1
    Passing an object to a routine to share underlying data is perfectly fine in C#, at least from a syntax perspective.
    – Brian
    Commented Aug 15, 2013 at 12:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.