Since the beginning of time, code editors have been equipped with ‘Find’ and / or ‘Find All’ features. This allows the user to search for any or all occurrences of literal text in a code base. Most editors also allow you to use regular expressions for more ‘advanced’ searches.
But what if you need to search for all variables with the name ‘goldCustomer’, because someone decided these need to be renamed to ‘specialCustomer’. Or search for methods with a set of tree parameters named “name”, “dateOfBirth” and "address”, because these need to be refactored to use a new Person class. Or your codebase is filled with another repeating pattern that seemed to be a good idea to someone at one point, but now hinders development big time. These kind of searches are not easily done with simple text search or regular expressions. You need a search tool that understands the syntax of your code in order to search for these kinds of patterns.
Fortunately we now have the Roslyn compiler engine that understands the structure of C# code and exposes this structure in the form of syntax trees. You can use these syntax trees to analyze code by creating custom analyzers like I did here. For ad-hoc searches in day to day work however writing a custom analyzer for one time use is just way to much work. It involves creating a new solution in a new visual studio instance, writing the code for the analyzer, debugging it in the experimental Visual Studio Instance and then install it into yet another instance in order to search your target code base. It would be nice if we could simplify this.
Frank Bakker talks about software development
How great teams can create great solutions
Tuesday, November 24, 2015
Saturday, September 26, 2015
Creating a Roslyn code fix for Interpolated Strings in C#
In my previous post I showed a possible pitfall with the new C# string interpolation feature. I also showed how I created a Roslyn code analyzer to find these possible problems. As promised I will now follow up with the code fix provider that will help save you some typing when this analyzer fires a diagnostic message. Along the way I hope to show that creating code fixes is not as complicated as it might look.
Because I used the 'Analyser With Code Fix' template when creating the solution, I also got a CodeFixProvider into my solution to start with. This is the class where we will be fixing the code by adding the call to Invariant around the interpolated string.
So our goal is that if we get a diagnostic warning like
we would like our code fix to replace it with something like:
var today = DateTime.Today;
WriteLine(Invariant($"The date is {today}"));
Because I used the 'Analyser With Code Fix' template when creating the solution, I also got a CodeFixProvider into my solution to start with. This is the class where we will be fixing the code by adding the call to Invariant around the interpolated string.
Thursday, September 3, 2015
C# String Interpolation best practices
In this post I will show you my thoughts on using the new C# string interpolation syntax with regard to formatting. I will try to define a best practice for using this new feature and then show how I created a Roslyn based code analyser that checks for this best practice.
Last week a colleague of mine showed us how he used the new C# String Interpolation feature in his project.
which is equivalent to
I responded that I like the new syntax, but the downside is that it uses the CurrentCulture of the executing thread as the FormatProvider. This makes the behaviour of this code dependant on the thread context which may lead to unexpected results.
Last week a colleague of mine showed us how he used the new C# String Interpolation feature in his project.
var requestUri = $"api/v1/Colors/{id}/Variants";
which is equivalent to
var requestUri = string.Format("api/v1/Colors/{0}/Variants",id);
I responded that I like the new syntax, but the downside is that it uses the CurrentCulture of the executing thread as the FormatProvider. This makes the behaviour of this code dependant on the thread context which may lead to unexpected results.
Reboot
Ok, let's state the Obvious: It has been a long time since I wrote a blog post. I have just finished transferring my old content to my new blog: Frank Bakker talks about software development. This way everything will stay together in a single archive.
I have recently started a new job at Aviva Solutions. At Aviva I will be doing what I love to do most: Help customers solve their complex problems by creating high quality software solutions with a team of highly skilled professionals.
For me this new start is a good opportunity to pick up blogging again. Writing a blog forces me to organize my thoughts about a subject in a way you can understand it. I hope this result in both you and me learning something new.
I have recently started a new job at Aviva Solutions. At Aviva I will be doing what I love to do most: Help customers solve their complex problems by creating high quality software solutions with a team of highly skilled professionals.
For me this new start is a good opportunity to pick up blogging again. Writing a blog forces me to organize my thoughts about a subject in a way you can understand it. I hope this result in both you and me learning something new.
Thursday, November 12, 2009
New coordination datastructures in .Net 4.0 Beta 2
To be honest a have not spent too much time looking at .Net 4.0 beta 2 yet. But I do keep up with the blogs concerning Parallel Extensions. Josh Philps has just posted an entry about the changes that were made in the Coordination Data Structures (CDS) in Beta 2. The CDS are the types that have been added to the framework that will help writing concurrent applications without having to do (to much of) your own synchronization. I used two of the CDS classes (ConcurrentDictionary<Tkey, TValue> and Lazy<T>) in the CacheDictionary that I wrote about in this article.
1: public class CacheDictionary<TKey, TValue>
2: where TValue : class // needs to be a ref type due to current limitation of lazyInit<>
3: {
4: ConcurrentDictionary<TKey, LazyInit<TValue>> _cacheItemDictionary = new ConcurrentDictionary<TKey, LazyInit<TValue>>();
5:
6: public TValue Fetch(TKey key, Funcproducer)
7: {
8: LazyInitcacheItem;
9: if (!_cacheItemDictionary.TryGetValue(key, out cacheItem))
10: {
11: cacheItem = new LazyInit(() => producer(), LazyInitMode.EnsureSingleExecution);
12:
13: if (!_cacheItemDictionary.TryAdd(key, cacheItem))
14: {
15: // while we never remove items, if TryAdd fails it should be present
16: cacheItem = _cacheItemDictionary[key];
17: }
18: }
19: return cacheItem.Value;
20: }
21: }
Tuesday, March 17, 2009
Visualizing Linq operators: The Info Support Linq Posters
Over the last few months I have been working on a little project to make Linq ‘come to life’ in two full size posters that developers can hang on the wall of their offices. The Linq posters demonstrates the usage of all Linq operators using visual sequences of female and male figures. Since this week the final result is ready and can be ordered in Print / Downloaded from our website http://www.infosupport.com/linq free of charge!
So why create a Linq poster?
Sunday, March 15, 2009
CacheDictionary for .Net 3.5, using ReaderWriterLockSlim ?
In my previous post I described how to create a thread safe data cache using PFX. PFX however is scheduled to be released as a part of the .Net framework 4.0 which means we will have to wait a while before we can use this in real world applications. That’s why I created an implementation using the generic Dictionary combined with a ReaderWriterLockSlim which are both available in .Net 3.5. today.
1: public class CacheDictionary
2: {
3: ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim();
4: Dictionary> _cacheItemDictionary = new Dictionary >();
5:
6: public TValue Fetch(TKey key, Funcproducer)
7: {
8: LazyInitcacheItem;
9: bool found;
10:
11: _cacheLock.EnterReadLock();
12: try
13: {
14: found = _cacheItemDictionary.TryGetValue(key, out cacheItem);
15: }
16: finally
17: {
18: _cacheLock.ExitReadLock();
19: }
20:
21: if (!found)
22: {
23: _cacheLock.EnterWriteLock();
24: try
25: {
26: if (!_cacheItemDictionary.TryGetValue(key, out cacheItem))
27: {
28: cacheItem = new LazyInit(producer);
29: _cacheItemDictionary.Add(key, cacheItem);
30: }
31: }
32: finally
33: {
34: _cacheLock.ExitWriteLock();
35: }
36: }
37:
38: return cacheItem.Value;
39: }
40: }
Subscribe to:
Posts (Atom)