Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

24/03/2017

Report from the battlefield #10 - fuck-up with AutoMapper

Home



Have you ever heard or used AutoMapper? What a question, of course you have. And in the very unlikely scenario that you haven't, it's the object to object mapper that allows you to map probably everything. In short no more manual, boring, tedious, error-prone mapping.

However, the great power comes with great responsibility. In the recent time, I had an occasion to fix 2 difficult to track bugs related to improper usage of AutoMapper. Both issues were related to the feature of AutoMapper which according to me is almost useless and at least should be disabled by default. Let's look at the following 2 classes and testing code:
public class SomeSourceClass
{
   public Guid Id { get; set; }
   public string IdAsString => Id.ToString();
   public string Value { get; set; }
}

public class SomeDestinationClass
{
   public Guid Id { get; set; }
   public string IdAsString => Id.ToString();
   public string Value { get; set; }
}

class Program
{ 
   static void Main()
   {
      Mapper.Initialize(config => config.CreateMap<SomeSourceClass,SomeDestinationClass>>());
      
      var src = new SomeSourceClass { Id = Guid.NewGuid(), Value = "Hello" };
      var dest = Mapper.Map<SomeDestinationClass>(src);

      Console.WriteLine($"Id = {dest.Id}");
      Console.WriteLine($"IdAsString = {dest.IdAsString}");
      Console.WriteLine($"Value = {dest.Value}");
   }
}
This works as a charm. If you run this example, you should see output like that:

Id = a2648b9e-60be-4fcc-9968-12a20448daf4
IdAsString = a2648b9e-60be-4fcc-9968-12a20448daf4
Value = Hello

Now, let's introduce interfaces that will be implemented by SomeSourceClass and SomeDestinationClass:
public interface ISomeSourceInterface
{
   Guid Id { get; set; }
   string IdAsString { get; }
   string Value { get; set; }
}

public interface ISomeDestinationInterface
{
   Guid Id { get; set; }
   string IdAsString { get; }
   string Value { get; set; }
}

public class SomeSourceClass: ISomeSourceInterface { /*... */}

public class SomeDestinationClass : ISomeDestinationInterface { /*... */}
We also want to support mappings from ISomeSourceInterface to ISomeDestinationInterface so we need to configure AutoMapper accordingly. Otherwise the mapper will throw an exception.
Mapper.Initialize(config =>
   {
      config.CreateMap<SomeSourceClass, SomeDestinationClass>();
      config.CreateMap<ISomeSourceInterface, ISomeDestinationInterface>();
   });

var src = new SomeSourceClass { Id = Guid.NewGuid(), Value = "Hello" };
var dest = Mapper.Map<ISomeDestinationInterface>(src);

Console.WriteLine($"Id = {dest.Id}");
Console.WriteLine($"IdAsString = {dest.IdAsString}");
Console.WriteLine($"Value = {dest.Value}");
If you run this code, it'll seemingly work as the charm. However, there is a BIG PROBLEM here. Let's examine more carefully what was written to the console. The result will look as follows:

Id = a2648b9e-60be-4fcc-9968-12a20448daf4
IdAsString =
Value = Hello

Do you see a problem? The readonly property IdAsString is empty. It seems crazy because IdAsString property only returns the value of Id property which is set. How is it possible?

And here we come the feature of AutoMapper which according to be should be disabled by default i.e. automatic proxy generation. When AutoMapper tries to map ISomeSourceInterface to ISomeDestinationInterface it doesn't know which implementation of ISomeDestinationInterface should be used. Well, actually no implementation may even exists, so it generates one. If we check the type of dest property we'll see something like:

Proxy<ConsoleApplication1.ISomeDestinationInterface_ConsoleApplication1_Version=1.0.0.0_Culture=neutral_PublicKeyToken=null>.

Initially this function may look as something extremely useful. But it's the Evil at least because of the following reasons:
  • As in the example, the mapping succeeds but the result object contains wrong data. Then this object may be used to create other objects... This can lead to really difficult to detect bugs.
  • If a destination interface defines some methods, a proxy will be generated, but the mapping will fail due to System.TypeLoadException.
  • It shouldn't be needed in the well written code. However, if you try to cast the result of the mapping to the class, then System.InvalidCastException exception will be thrown.
The ideal solution would be to disable this feature. However, I don't know how :( The workaround is to explicitly tell AutoMapper not to generate proxies. To do that we need to use As method and specify which concrete type should be created instead of a proxy.

The final configuration looks as follows. It's also worth mentioning that in this case we actually don't need to define mapping from SomeSourceClass to SomeDestinationClass. AutoMapper is clever enough to figure out that these classes implements interfaces.
Mapper.Initialize(
   config =>
   {
      config.CreateMap<ISomeSourceInterface, ISomeDestinationInterface>().As<SomeDestinationClass>();
   });


AutoMapper proxy generation feature is the Evil.


*The picture at the beginning of the post comes from own resources and shows Okonomiyaki that we ate in Hiroshima. One of the best food we've ever eaten.

15/03/2017

Report from the battlefield #9 - async/await + MARS

Home



This post from Report from the battlefield series will be about my own mistake. It is related to async/await and MARS i.e. Multiple Active Result Sets. async/await allows us to use asynchronous programming more easily. MARS is a feature of MSSQL that allows us to have more than one pending request opened per connection at the same time. For example, it may be useful if we have 2 nested loops i.e. internal and external. External loops iterate through one result set and the internal one through another. Ok, but you probably wonder what MARS has in common with async/await.

A few days ago my application started failing due to InvalidOperationException exception with the additional message saying that The connection does not support MultipleActiveResultSets. Well, I used MARS in the past so I simply enabled it in the connection string by setting MultipleActiveResultSets attribute to true.

However, later I realized that my application should not require MARS at all so I started digging into what was wrong. It turned out that the problem was related to my silly mistake in using async/await. Let's look at the following simplified version of the problematic code. We have a trivial Main method:
static void Main()
{
   Start().GetAwaiter().GetResult();
}
Start is an async method responsible for opening a connection to DB and executing other async methods:
private static async Task Start()
{
   using (var c = new SqlConnection(ConnectionString))
   {
      c.Open();

      await Func1(c);
      await Func2(c);
      await Func3(c);
   }
}
Func1, Func2 and Func3 are responsible for reading data and processing them. In our case, for simplification, they all will do the same thing:
private static async Task Func1(SqlConnection c) => await ReadData(c);
private static async Task Func2(SqlConnection c) => ReadData(c);
private static async Task Func3(SqlConnection c) => await ReadData(c);
And here is the ReadData method. It's also simple. It simply reads data from a table:
private static async Task ReadData(SqlConnection c)
{
   var cmd = c.CreateCommand();

   cmd.CommandText = "SELECT * FROM dbo.Fun";

   using (var reader = await cmd.ExecuteReaderAsync())
   {
      while (await reader.ReadAsync())
      {
         // Process data
      }
   }
}
If you run this code, the aforementioned InvalidOperationException exception will be thrown in the line with ExecuteReaderAsync. The question is why? Well, in this short code it is rather easy to spot that in Func2 method await is missing before ReadData. But, do you know why it is a problem? If not, don't worry it's a little bit tricky.

Here is an explanation. Without await the simplified flow is as follows:
  • ...
  • Start executes Func2.
  • Func2 executes ReadData.
  • ReadData executes ExecuteReaderAsync.
  • ReadData awaits for the result from ExecuteReaderAsync.
  • The control returns to caller i.e. Func2.
  • However, Func2 does not use await so it returns completed task to Start method.
  • From the point of view of Start processing of Func2 is finished so it executes Func3.
  • Func3 executes ReadData
  • The previous call to ReadData may be still in progress.
  • It also means that ReadData will call ExecuteReaderAsync when another result set is still being processed.
  • The exception is thrown.
Adding missing await fix the problem. Thanks to that the task returned from Func2 will not be completed until call to ReadData is over. And if so Start will not execute Func3 immediately. The final well known conclusion is:

Always async/await all the way down.


*The picture at the beginning of the post comes from own resources and shows Laurel forest on La Gomera.

31/10/2016

Roslyn - How to create a custom debuggable scripting language 2?

Home


A screenshot comes from Visual Studio 2015

In the previous post I explained how to create a simple debuggable scripting language based on Roslyn compiler as a service. By debuggable I mean that it can be debugged in Visual Studio as any "normal" program for example written in C#.

27/10/2016

Roslyn - How to create a custom debuggable scripting language?

Home


A screenshot comes from Visual Studio 2015

Sometime ago I decided to play a little bit with Cakebuild. It's a build automation tool/system that allows you to write build scripts using C# domain specific language. What's more it is possible to debug these scripts in Visual Studio. It is interesting because Cake scripts are neither "normal" C# files nor are added to projects (csproj). I was curious how it was achieved and it is result of my analysis. I'll tell you how to create a simple debuggable scripting language. By debuggable I mean that it'll be possible to debug scripts in our language in Visual Studio almost as any "normal" program in C#. Cakebuild uses Roslyn i.e. a compiler as a service from Microsft and we'll do the same.

27/07/2015

A hint how to use TaskCompletionSource<T>

Home

Some time ago I wrote about using TaskCompletionSource<T> class in order to take advantage of async/await keywords. In that post I included the following code:
public async Task<Stream> ProcessFileAsync(string key, string secret, string path)
{
   var client = new DropNetClient(key, secret);
   //...
   var tcs = new TaskCompletionSource<Stream>();
   client.GetFileAsync(path, response => tcs.SetResult(new MemoryStream(response.RawBytes)), tcs.SetException);
   return tcs.Task;
}
Now, Let's assume that we want to provide a possibility to cancel a task returned from ProcessFileAsync method. We can do something like that:
public async Task<Stream> ProcessFileAsync(string key, string secret, string path, CancellationToken ct)
{
   var client = new DropNetClient(key, secret);
   //...
   var tcs = new TaskCompletionSource<Stream>();

   ct.Value.Register(tcs.SetCanceled);

   client.GetFileAsync(path, response => tcs.SetResult(new MemoryStream(response.RawBytes)), tcs.SetException);
   return tcs.Task;
}
I used CancellationToken.Register method in order to register a callback that will be executed when a token is canceled. This callback is responsible for notifying TaskCompletionSource<T> that underlying task should be cancelled.

You may say that it is not enough because this code doesn't inform DropNetClient that an action should be cancelled. You are right. However, according to my knowledge DropNet API doesn't provide such a possibility.

It leads to the situation when a task is cancelled but DropNetClient continues processing and finnaly TaskCompletionSource.SetResult method will be executed. This will cause ObjectDisposedException because this method cannot be executed for a disposed task. What can we do in this case?

The first solution is to check if a task is cancelled before calling SetResult method. However, it can still happen that a task will be cancelled after this check but before calling SetResult method.

My proposition is to use methods from TaskCompletionSource.Try* family. They don't throw exceptions for disposed tasks.
public async Task<Stream> ProcessFileAsync(string key, string secret, string path, CancellationToken ct)
{
   var client = new DropNetClient(key, secret);
   //...
   var tcs = new TaskCompletionSource<Stream>();

   ct.Value.Register(tcs.SetCanceled);

   client.GetFileAsync(path, response => tcs.TrySetResult(new MemoryStream(response.RawBytes)), tcs.TrySetException);
   return tcs.Task;
}
I'm aware that it is not a perfect solution because it actually does not cancel processing. However, without modifying DropNet code it is not possible. It the case of my application it is an acceptable solution but it is not a rule.

16/07/2015

Interview Questions for Programmers by MK #5

Home

Question #5
Here you have a very simple implementation of Template method pattern.
public abstract class BaseAlgorithm
{
   protected SomeObject Resource { get; set; }
   //Other resources

   public void Start()
   {
      // Configure
      Resource = new SomeObject();
      //...
      try
      {
         InnerStart();
      }
      finally
      {
         // Clean up
         Resource.Dispose();
         Resource= null;               
         //...
      }
   }

   protected abstract void InnerStart();
}

public class Algorithm1: BaseAlgorithm
{
   protected override void InnerStart()
   {
      //Do something with allocated resources
   }  
}
At some point someone decided to create a new class Algorithm2 derived from BaseAlgorithm. The difference between the new class and the previous one is that Algorithm2 starts an asynchronous operation. A programmer decided to use async/await keywords to handle this scenario. What do you think about this approach? What could possibly go wrong?
public class Algorithm2: BaseAlgorithm
{
   protected async override void InnerStart()
   {
      var task = DoAsyncCalculations();
      await task;

      //Do something with allocated resources
   }

   private Task DoAsyncCalculations()
   {
      //Let's simulate asynchronous operation
      return Task.Factory.StartNew(() => Thread.Sleep(1000));
   }
}
Answer #5
I think that the developer who created Algorithm2 doesn't understand well how async/await keywords work. The main problem is that finally block inside Start method will be executed before DoAsyncCalculations method will end calculations. In other words resources will be disposed in the middle of calculations and this will cause an exception. Sequence of events will be as follows:
  • Start method begins.
  • SomeObject is created.
  • InnerStart method begins.
  • InnerStart method starts an asynchronous operation and uses await to suspend its progress.
  • This causes that control returns to Start method.
  • Start method cleanups resources.
  • When the asynchronous operation is finished InnerStart method continues processing. It tries to use resources, that have been already disposed, what leads to an exception.
It is also not recommended to have async void methods (except event handlers). If an async method doesn't return a task it cannot be awaited. It is also easier to handle exceptions if an async method returns a task. For details see also this article.

To fix a problem BaseAlgorithm must be aware of asynchronous nature of calculations. For example InnerStart method can return a task which will be awaited inside try block. However, it also means that synchronous version of InnerStart method in Algorithm1 will have to be changed. It may not be acceptable. Generally, providing asynchronous wrappers for synchronous methods is debatable and should be carefully considered.

In this case, I'll consider to have separated implementations of Template method pattern for synchronous and asynchronous algorithms.

06/07/2015

A practical example of using TaskCompletionSource<T>

Home

Recently I've found a question about real life scenarios for using rather unknown TaskCompletionSource<T> class. I started thinking where I would use it and very quickly I found a good practical example.

I have a pet project LanguageTrainer that helps me in learning words in foreign languages. Some time ago I added Dropbox support to it. It allows me to export/import list of words to/from Dropbox. I developed it in synchronous way. Now I prefer an asynchronous approach and I want to take advantages of async/await keywords.

The problem is that DropNet library, that makes communication with Dropbox easy, doesn't use async/await. It has asynchronous API but it is callback based. The really easy solution here is to use TaskCompletionSource<T>. Here is an example (simplified). Let's start with the original code that downloads a given file from Dropbox.
public void ProcessFile(string key, string secret, string path)
{
   var client = new DropNetClient(key, secret);
   // ...
   var bytes = client.GetFile(path)
   //Process bytes
}
The version that uses DropNet asynchronous API looks in the following way:
public void ProcessFileAsync(string key, string secret, string path)
{
   var client = new DropNetClient(key, secret);
   //...
   client.GetFileAsync(path, 
      response => 
      {
         var bytes = response.RawBytes;
         //Process bytes
      }, 
      ex => 
      {
         //Handle exception
      });
}
And finally the asynchronous version with async/await looks in the following way:
public async Task<Stream> ProcessFileAsync(string key, string secret, string path)
{
   var client = new DropNetClient(key, secret);
   //...
   var tcs = new TaskCompletionSource<Stream>();
   client.GetFileAsync(path, response => tcs.SetResult(new MemoryStream(response.RawBytes)), tcs.SetException);
   return tcs.Task;
}
...
var bytes = await ProcessFileAsync(key, secret, path);
//Process bytes
The method ProcessFileAsync is marked as async and returns a task so it can be awaited. Easy. isn't it? A few lines of code and you can use async/await with other types of asynchronous APIs.

23/04/2015

How to build predicates dynamically using expression trees

Home

I'm working at the application which finds so called execution patterns in logs recorded by IntelliTrace historical debugger. An execution pattern is a sequence of methods calls that is widely used in the application and it is a kind of automatically generated documentation. The part of the algorithm is filtering of found patterns based on criteria like the length of a pattern or the number of different methods in a pattern.

At the beginning I used only 2 criteria so it was easy to handle all possible combinations of them i.e. use the first criterion, use the second criterion, use both and used none. Then I added 3rd criterion and I thought that for 3 criteria I still don't need a generic mechanism. However, shortly it turned out that I want to handle 5 criteria what gives 32 of possible combinations. This time I did it once and for all.

I decided to use expression trees to dynamically build an expression that verifies any combination of criteria. The code is quite simple. Firstly we need an enum for all criteria.
[Flags]
public enum Crieria : byte
{
    None = 0,
    CriterionOne = 1,
    CriterionTwo = 2,
    All = CriterionOne | CriterionTwo
}
We also need a class that will represent patterns.
public class Pattern
{
    public int FieldOne { get; set; }
    public int FieldTwo { get; set; }
}
Now we can write a code that will dynamically build needed expressions. I assumed that every criterion has a corresponding static method that knows how to check if a current pattern fulfils it or not. The final expression produced by CreateExpression method will be of the following form pattern => predicate1(pattern) && predicate2(pattern) && predicate3(pattern)....
public static class FilterBuilder
{
    public static Func<Pattern, bool> CreateExpression(Crieria filteringMode)
    {
        var param = Expression.Parameter(typeof(Pattern));

        var subExpressions = new List<MethodCallExpression>();

        if ((filteringMode & Crieria.CriterionOne) != 0)
            subExpressions.Add(Expression.Call(typeof(FilterBuilder), nameof(CriterionOnePredicate), null, param));

        if ((filteringMode & Crieria.CriterionTwo) != 0)
            subExpressions.Add(Expression.Call(typeof(FilterBuilder), nameof(CriterionTwoPredicate), null, param));

        //Other criteria...

        if (subExpressions.Count == 0)
            return p => true;

        Expression finalExpression = subExpressions[0];
        for (var i = 1; i < subExpressions.Count; ++i)
            finalExpression = Expression.And(finalExpression, subExpressions[i]);

        return Expression.Lambda<Func<Pattern, bool>>(finalExpression, param).Compile();
    }

    public static bool CriterionOnePredicate(Pattern p)
    {
        return p.FieldOne > 0;
    }

    public static bool CriterionTwoPredicate(Pattern p)
    {
        return p.FieldTwo < 0;
    }
}
The code can be made even more generic but I'll leave it as an exercise. When I finished this code I started to worry about performance. It is critical for me because my application needs to process large amount of patterns efficiently. I made the following simple test in which dynamically generated and static functions are executed 1 million times.
var iterations = 1000000;

var predicate = FilterBuilder.CreateExpression(Crieria.All);
MeasureIt<Pattern>((p) => predicate(p), new Pattern(), iterations);

predicate = FilterBuilder.CreateExpression(Crieria.CriterionOne);
MeasureIt<Pattern>((p) => predicate(p), new Pattern(), iterations);

MeasureIt<Pattern>((p) =>
{
   FilterBuilder.CriterionOnePredicate(p);
   FilterBuilder.CriterionTwoPredicate(p);
}, new Pattern(), iterations );

MeasureIt<Pattern>((p) => FilterBuilder.CriterionOnePredicate(p), new Pattern(), iterations);
In order to measure time of calculations I used MeasureIt method from my earlier post and I received the following results:
Total time: 54
Total time: 27
Total time: 18
Total time: 12
Dynamically generated predicates are 2-3 times slower than static ones. However, we are still talking here about dozens of milliseconds in order to make 1 million calls. For me it is acceptable.

18/04/2015

What every blogger should do if using someone else's code #1

Home

The developer's work very often involves effective re-using of a code that was written by someone else. Sometime these are fully fledged libraries or frameworks but sometimes these are also small or even very small pieces of code found on a blog or a forum. All this stuff makes our life easier.

When I use someone else's code in my project I wonder if it is worth writing about it on my blog. And sometimes I hesitate. Why? Because it is a well know library and there is a lot about it in Internet. Sometimes because I don't have time to write a tutorial. And sometimes because I think that there is no much to write about,that it is a small piece of code so everybody can understand it on their own.

Now, I think that it is a wrong approach. Maybe it is small, but I used it so it means that I din't have to design, write and test it on my own. Maybe I don't have time to write a tutorial but this code actually saved me time that I'm lacking.

So, what should I (we) do? Just write a short note on our blogs and say that we used this and this in our projects. At least in this way we can thank the authors.

To start. In WPF there is a class GridSplitter that allows user to resize rows and columns in a grid. However, I wanted the same functionality for DockPanel but WPF doesn't provide it. I decided that I'll wrote it but firstly I goggled for something like that and I found this article. The DockPanelSplitter class has 300 lines of code, it is not complex but works well. Give it a chance.

22/01/2015

DateTime.Parse vs DateTime.ParseExact

Home

Ostatnio spotkałem się z taka sytuacją. Ktoś zdefiniował sobie dość specyficzny format daty na swoje potrzebny. Wszystko było ok kiedy był on używany do zamiany typu DateTime na ciąg znaków. Problemy zaczęły się przy próbie wykonania operacji odwrotnej. Okazało się, że rodzina metod DateTime.(Try)Parse sobie z tym nie radzi. Rozwiązaniem okazało się użycie metod z rodziny DateTime.(Try)ParseExact, która od tych wcześniejszych różni się tym, że jawnie wymaga podania formatu, który ma zostać użyty przy parsowaniu.

Postawione pytanie brzmiało czemu DateTime.(Try)Parse nie działa w tym przypadku, a w innych tak? Moja odpowiedź jest taka. Nie wiem czemu podjęto taką decyzję, ale DateTime.(Try)Parse nie obsługuje wszystkich możliwych formatów i to nawet jeśli kultura używana przez aplikację zawiera wszystkie potrzebne informacje. Oto fragment z dokumetnacji:

If you parse a date and time string generated for a custom culture, use the ParseExact method instead of the Parse method to improve the probability that the parse operation will succeed. A custom culture date and time string can be complicated, and therefore difficult to parse. The Parse method attempts to parse a string with several implicit parse patterns, all of which might fail.

A to jeszcze jeden:

The Parse and TryParse methods do not fully iterate all strings in patterns when parsing the string representation of a date and time. If you require a date and time string to have particular formats in a parsing operation, you should pass the array of valid formats to the DateTime.ParseExact...

W skrócie DateTime.(Try)Parse jest z założenia "upośledzone" i nie umie wszystkiego. Dlaczego? Może dlatego, że obsłużenie wszystkich możliwych przypadków jest bardzo trudne? A może dlatego, że gdyby napisano kombajn obsługujący wszystko to działałby wolno? To tylko zgadywanie, ale trzeba pamiętać, że:

Jeśli używamy własnych formatów daty i czasu to zaleca się użycie DateTime.(Try)ParseExact.

06/10/2014

OxyPlot i nieciągłe przedziały

Home

Od dłuższego czasu używam biblioteki OxyPlot i bardzo ją sobie chwalę. Ostatnio zamarzyło mi się stworzenie wykresu przedziałowego. Na początek stwierdziłem, że wystarczy zastosować zwykły wykres liniowy czyli klasę LineSeries. Załóżmy, że chcemy zaprezentować na wykresy przedziały tj.; (2,3), (4,6) oraz (8,10). Spróbujmy, więc czegoś takiego:
var s = new LineSeries();
s.Title = "Nieciągłe przedziały";
s.Points.Add(new DataPoint(2, 1));
s.Points.Add(new DataPoint(3, 1));
           
s.Points.Add(new DataPoint(4, 1));
s.Points.Add(new DataPoint(6, 1));
        
s.Points.Add(new DataPoint(8, 1));
s.Points.Add(new DataPoint(10, 1));
To jednak nie zadziała gdyż w rezultacie otrzymamy linię ciągłą, czego zresztą należało się spodziewać ponieważ LineSeries po prostu łączy kolejne punkty. Wypróbowałem więc inne rodzaje wykresów, bawiłem się ustawieniami, ale bez rezultatów. Rozwiązanie okazało się jednak bardzo proste. Jeśli nie chcemy, aby dwa punkty zostały połączone linią to pomiędzy nimi należy umieścić punkt o współrzędnych (Double.Nan, Double.NaN).
var s = new LineSeries();
s.Title = "Nieciągłe przedziały";
s.Points.Add(new DataPoint(2, 1));
s.Points.Add(new DataPoint(3, 1));
s.Points.Add(new DataPoint(Double.NaN, Double.NaN));            
s.Points.Add(new DataPoint(4, 1));
s.Points.Add(new DataPoint(6, 1));
s.Points.Add(new DataPoint(Double.NaN, Double.NaN));       
s.Points.Add(new DataPoint(8, 1));
s.Points.Add(new DataPoint(10, 1));
Na koniec jeszcze przykład tak skonstruowanego wykresu:

21/09/2014

Od jakiej wartości zaczynają się indeksy tablic w C#?

Home

To post z serii ciekawostki. Większość z Was zapytana od jakiej wartości zaczynają się indeksy tablic w C# odpowie z pewnością, że od 0 i tego należy się trzymać, ale są pewne wyjątki. Oto przykład na jaki natknąłem się eksplorując czeluście platformy .NET pokazujący jak stworzyć tablicę 10x10 z indeksami zaczynającymi się od 5:
var array = Array.CreateInstance(typeof(int), new[] { 10, 10 }, new[] { 5, 5 });
var array2 = (int[,]) array;
A teraz mały przykład użycia:
array2[1,3] = 1 // Out of bounds array index
array2[5,6] = 1 // OK
array2[15,14] = 1 // Out of bounds array index
array2[14,14] = 1 // OK
Oczywiście nie byłbym sobą gdybym nie spróbował tego samego z tablicą jednowymiarową:
var array = Array.CreateInstance(typeof(int), new[] { 10 }, new[] { 5 });
var array2 = (int[]) array;
Taka próba rzutowania zakończy się niestety, a może na szczęście, wyjątkiem o treści:

Unable to cast object of type 'System.Int32[*]' to type 'System.Int32[]'.

Co oznacza zapis System.Int32[*]? Mówiąc szczerze nie jest do końca pewny. Bazując jednak na poniższym teście:
Console.WriteLine(new int[10].GetType()); 
Console.WriteLine(Array.CreateInstance(typeof(int), new[] { 10 }, new[] { 0 }).GetType());
Console.WriteLine(Array.CreateInstance(typeof(int), new[] { 10 }, new[] { 5 }).GetType()); 
Console.WriteLine(new int[10,10].GetType()); 
Console.WriteLine(Array.CreateInstance(typeof(int), new[] { 10, 10 }, new[] { 5, 5 }).GetType()); 
Który wypisze na ekran takie wyniki:

System.Int32[]
System.Int32[]
System.Int32[*]
System.Int32[,]
System.Int32[,]

Można stwierdzić, że nazwa typu TYP[*] oznacza po prostu tablicę jednowymiarową z indeksem nie zaczynającym się w zerze.

Na koniec jeszcze jedna ciekawostka. Rzutowanie System.Int32[*] na System.Int32[] w kodzie programu nie powiedzie się, ale już w oknie Quick Watch albo Immediate Window już tak:

17/09/2014

Zużycie procesora przez wskazany proces

Home

Potrzebowałem ustalić programowo bieżące zużycie procesora przez wskazany proces. Zacząłem od przyjrzenia się licznikom wydajności i szybko naklepałem coś takiego:
var p = Process.GetProcessById(id);
var counter = new PerformanceCounter("Process", "% Processor Time", myProcess.ProcessName);
Console.WriteLine("Processor %: {0}", counter.NextValue());
Przetestowałem i wyniki okazały się dziwne ponieważ czasami uzyskiwałem zużycie większe niż 100%. Chwila, ale przecież mam 8 rdzeniowy procesor. Spróbujmy więc czegoś takiego:
Console.WriteLine("Processor %: {0}", counter.NextValue() / Environment.ProcessorCount);
To już działało dobrze. Postanowiłem jednak poszukać alternatywnego sposobu i przyjrzałem się co oferuje klasa Process. Szybko znalazłem właściwość Process.TotalProcessorTime, która zgodnie ze swoją nazwą zwraca całkowity czas procesora zużyty przez dany proces począwszy od jego uruchomienia. Ja potrzebowałem natomiast aktualnego zużycia. Trochę myślenia, szukania w Internecie (na przykład tutaj) i szybko dopisałem coś takiego:
public class Utils
{
    public class ProcessorUtilizationInfo
    {
        public TimeSpan LastProcessorTime { get; set; }
        public DateTime LastCheck { get; set; }
        public double Value { get; set; }
        public Process Process { get; set; }
    }

    public static ProcessorUtilizationInfo GetProcessorUtilization(ProcessorUtilizationInfo info)
    {
        info.Process.Refresh();

        var now = DateTime.Now;
        var elapsed = now - info.LastCheck;
        var processorTime = (info.Process.TotalProcessorTime - info.LastProcessorTime);

        info.LastProcessorTime = info.Process.TotalProcessorTime;
        info.LastCheck = now;
        info.Value = processorTime.TotalMilliseconds / elapsed.TotalMilliseconds / Environment.ProcessorCount;

        return info;
    }
}
Dla przejrzystości pominąłem walidację danych. Klasa pomocnicza ProcessorUtilizationInfo jest potrzebna gdybyśmy chcieli wołać metodę GetProcessorUtilization wielokrotnie dla tego samego procesu. Ktoś może marudzić, że używam DateTime.Now, że wynik może być nieprecyzyjny, ale moje testy pokazały, że zastosowanie licznika wydajności i metody GetProcessorUtilization daje podobny rezultaty. Przykład użycia metody GetProcessorUtilization wygląda następująco:
var p = Process.GetProcessById(id);
var info = new Utils.ProcessorUtilizationInfo {Process = p};
Console.WriteLine("Processor %: {0}", Utils.GetProcessorUtilization(info).Value * 100);
Do opisanych 2 sposobów uzyskania aktualnego zużycia procesora dla wskazanego procesu mam jedno zastrzeżenie. Otóż oba rozwiązania dają co prawda bardzo zbliżone wyniki (zaobserwowałem różnice rzędu 0.1 - 0.2%), ale wyniki te różniły się nawet o 1% od tego co pokazywał menadżer zadań. Ktoś wie dlaczego? Może znacie lepsze rozwiązanie postawionego problemu?

17/05/2014

Przydaś do rysowania wykresów

Home

Od jakiegoś czasu sporo pracuję z różnymi seriami danych numerycznych np.: sekwencje identyfikatorów metod wywołanych w programie. Serie takie mogą być bardzo długie i potrzebowałem narzędzia, które łatwo i szybko pozwoli mi je wizualizować czyli wygenerować wykres, tak abym mógł szybko ocenić co znajduje się w danym pliku. Kombajnów do rysowania wykresów jest dużo, choćby Excel, ale ja potrzebowałem czegoś jeszcze prostszego. Idealnie abym mógł po prostu zaznaczyć plik z danymi i z menu kontekstowego wybrać polecenie Narysuj wykres. Możliwe, że znalazłbym coś takiego, ale napisanie takie narzędzia samemu zajęło mi dosłownie chwilę.

Po pierwsze zdecydowałem się użyć biblioteki OxyPlot bo jest bardzo prosta w użyciu, a także radzi sobie z długimi seriami danych i pozwala narysować wiele różnych typów wykresów. W drugim kroku stworzyłem bardzo prostą aplikację z jednym oknem w WPF'ie. Do projektu dodałem referencje do bibliotek OxyPlot oraz OxyPlot.Wpf. XAML dla głównego i jedynego okna wygląda w następujący sposób:
<Window x:Class="DrawPlot.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:oxy="http://oxyplot.codeplex.com"
        xmlns:local="clr-namespace:DrawPlot"
        Title="DrawPlot" Height="350" Width="525">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <oxy:Plot Model="{Binding MyModel}"/>
    </Grid>
</Window>
Trzeci krok to napisanie klasy MainViewModel, która stworzy i zainicjuje obiekt klasy PlotModel. Obiekt ten będzie zawierał informacje potrzebne do narysowania wykresu i przy pomocy binding'u zostanie przekazany do kontrolki Plot. W podstawowej wersji kod tej klasy jest bardziej niż prosty. Zakładam z góry określony format pliku wejściowego tj. każda linia zawiera jedną liczbę, a część ułamkowa musi być oddzielona od części całkowitej kropką. Użyłem klasy LineSeries czyli rysuję wykres liniowy. W poniższym kodzie celowo pominąłem również bardziej przyjazną obsługę błędów czyli jeśli coś się nie powiedzie to po prostu wyświetlam treść błędu i zamykam aplikację.
namespace DrawPlot
{
    public class MainViewModel
    {
        public PlotModel MyModel { get; private set; }

        public MainViewModel()
        {
            try
            {
                var args = Environment.GetCommandLineArgs();

                var lines = File.ReadAllLines(args[1]);

                var lineSeries = new LineSeries();
                for (var i = 0; i < lines.Length; ++i)
                    lineSeries.Points.Add(new DataPoint(i, Double.Parse(lines[i], CultureInfo.InvariantCulture)));

                var model = new PlotModel(Path.GetFileName(args[1]));
                model.Series.Add(lineSeries);
                MyModel = model;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                Application.Current.Shutdown();
            }
        }
    }
}
Ostatni krok to dodanie nowej pozycji do menu kontekstowego. Uzyskałem to przy pomocy dodania odpowiedniego wpisu w rejestrze. W moim przypadku skompilowana aplikacja znajduje się w lokalizacji T:\bin\DrawPlot\DrawPlot.exe.
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\Shell\Draw plot]

[HKEY_CLASSES_ROOT\*\Shell\Draw plot\command]
@="T:\\bin\\DrawPlot\\DrawPlot.exe \"%1\""
Narzędzie jest bardzo proste, ale spełnia swoje zadanie. Możne je również łatwo rozbudować na przykład użyć innego rodzaju serii aby narysować wykres kołowy, dodać obsługę innych formatów plików wejściowych itd.

27/03/2014

SizeLimit, PageSize i dokumentacja

Home

W poście wspomniałem o właściwościach DirectorySearcher.SizeLimit oraz DirectorySearcher.PageSize, których poprawne ustawienie zapewnia, że z bazy danych AD można pobrać więcej obiektów niż ustawiony na serwerze limit. Tym razem chciałbym sprecyzować do czego służą obie właściwości bo moim zdaniem dokumentacja nie jest precyzyjna, co potwierdza zresztą spora liczba pytań w Internecie na ten temat.

Otóż SizeLimit określa maksymalną liczbę obiektów jaka może zostać zwrócona w wyniku wyszukiwania (zero oznacza brak limitu) przy czym limit ustawiony na serwerze ma priorytet. PageSize służy natomiast do skonfigurowania stronicowania i wartość różna od zera je włącza. Na przykład wartość 100 oznacza, że obiekty będą zwracane w paczkach po 100, przy czym .NET jest na tyle miły, że samemu obsługuje doczytywanie kolejnych stron.

Teraz spójrzmy na przykład. W bazie danych AD znajdowało się 1580 obiektów spełniających kryteria wyszukiwania, a limit ustawiony na serwerze wynosił 1500. Poniższa tabelka pokazuje ile obiektów zwróci zapytanie w zależności od ustawień.

SizeLimitPageSizeLiczba obiektów w ADLiczba zwróconych obiektówUwagi
0015801500Brak stronicowania + domyślny limit z serwera
10001580100Brak stronicowania + limit określony przez nas
010015801580Stronicowanie włączone
20010015801580Stronicowanie włączone + limit określony przez nas
1002001580100Stronicowanie włączone + limit określony przez nas

Dwa ostatnie scenariusze są trochę zagadkowe. W obu przypadkach obie właściwości są różne od zera, ale liczba zwróconych obiektów jest inna tj. jeśli SizeLimit > PageSize to z AD pobrano wszystkie dostępne obiekty, a w przeciwnym wypadku tyle ile wynosił SizeLimit. Przypuszczam, że DirectorySearcher działa tak, że pobiera dane póki nie zostanie przekroczony limit. W pierwszym przypadku przy pobieraniu kolejnych stron liczba pobieranych obiektów nie przekracza limitu, a więc udało się odczytać wszystko. W drugim wypadku już przy pobraniu pierwszej strony liczba obiektów przekroczyła limit i dalsze pobieranie zostało zakończone. Pewnie można było to zaimplementować inaczej, ale cóż zrobić i po prostu warto o tym wiedzieć.

12/09/2013

Nullable<T>.Equals(T value) 2

Home

Pytanie o opinię na temat Nullable<T>.Equals(T value) z poprzedniego postu zadałem również na portalu stackoverflow. Jeden z odpowiadających bardzo słusznie zwrócił uwagę, że opisany przeze mnie "problem" nie dotyczy tylko typu Nullable<T>. Aby przekonać się o czym mowa uruchomcie następujący kod:
Console.WriteLine((2m).Equals(2));
Console.WriteLine((2).Equals(2M));
Pierwsza myśli to 2xTrue ale poprawny wynik to True, False. Dzieje się tak ponieważ istnieje niejawna kowersja z typu int na decimal ale nie na odwrót. Czyli w pierwszym przypadku zostanie użyta metoda Equals(decimal value), a w drugim Equals(object value) A piszę o tym ponieważ to jedna z tych rzeczy, o których bardzo łatwo zapomnieć.

11/09/2013

Nullable<T>.Equals(T value)

Home

Po dłuższej urlopowej przerwie w blogowaniu zacznę od zagadki z serii co zostanie wypisane na ekran, którą podsunął mi kolega Przemek:
decimal d = 2;

Console.WriteLine("d == 2 = {0}", d == 2);
Console.WriteLine("d == (decimal)2 = {0}", d == (decimal)2);

Console.WriteLine("d.Equals(2) = {0}", d.Equals(2));
Console.WriteLine("d.Equals((decimal)2) = {0}", d.Equals((decimal)2));
Tutaj jeszcze nie ma haczyka i odpowiedź to 4XTrue. Zmieńmy jednak jedną liniję:

decimal? d = 2;

Tym razem odpowiedź jest mniej oczywista. Na ekran zostanie wypisane: True, True, False, True. Czym więc różni się pierwsze wywołanie Equals od drugiego?

W obu przypadkach wołana jest metoda wirtualna. W obu przypadkach metoda ta wołana jest dla struktury Nullable<T>. Zmienna d nie jest null'em, a więc to też nie jest problemem. Spójrzmy zatem jak zaimplementowano Equals dla Nullable<T>:
public override bool Equals(object other)
{
    if (!this.HasValue)
    {
        return (other == null);
    }
    if (other == null)
    {
        return false;
    }
    return this.value.Equals(other);
}
Nic skomplikowanego, jeśli zmienna jest ustawiona to ponownie wywoływana jest metoda Equals w tym przypadku Decimal.Equals Odpowiedzi musimy szukać więc dalej. Wszystkie typy numeryczne mają przeciążoną metodę Equals w następujący sposób:
public override bool Equals(object value)
public override bool Equals(decimal value)
Która z nich zostanie wywołana w tej sytuacji? Nullable<T>.Equals ma parametr typu object, a więc Decimal.Equals(object value) pasuje lepiej niż Decimal.Equals(decimal value). Ta pierwsza działa natomiast w ten sposób, że jeśli przekazany parametr nie jest typu decimal to zawsze zwraca false nie sprawdzając czy przekazany obiekt można bezpiecznie konwertować na decimal. I ot cała tajemnica ;)

Moim zdaniem działanie Nullable<T> nie jest teraz intuicyjne. Wzorując się na typach numerycznych, można by dopisać do Nullable<T> jeszcze jedną metodę:
public bool Equals(T other)
{
    if (!this.HasValue)
        return false;

    return this.value.Equals(other);
}
Z jakiegoś powodu tego nie zrobiono. Przeoczenie czy celowe działanie? Jestem ciekawy Waszych opinii.

21/07/2013

Przykład przeglądu kodu i co z tego wynikło

Home

Jakiś czas temu robiłem przegląd kodu i zwróciłem uwagę na taki fragment implementacji:
public class SrvObject
{
   public int Id { get; set; }
   public string Code { get; set; }
   ...
}
...
private Dictionary<int, SrvObject> _cache = new Dictionary<int, SrvObject>();
...
if (_cache.Values.Any(x => x.Code == codeToFind))
{
   var obj = _cache.Values.FirstOrDefault(x => x.Code == codeToFind);
   ...
}
else
{
   var obj = ReadObject(codeToFind);
   _cache.Add(obj.Id, obj);
   ...
}
Zacznijmy od tego, że mamy klasę, która modeluje jakąś encję z bazy danych i ta encja posiada zarówno identyfikator (wewnętrzny dla systemu) oraz kod, który można na przykład wyświetlić użytkownikowi.

Programista użył słownika, z kluczem w postaci identyfikatora, aby buforować już odczytane z bazy danych encje. Pierwsza rzecz jaka rzuca się w oczy to fakt, że kluczem jest identyfikator, a my wyszukujemy na podstawie kodu co wymaga iterowania po wszystkich zgromadzonych w słowniku obiektach. Wynika to z tego, że w większości przypadków posługujemy się identyfikatorem, a tylko czasami kodem i wspomniany kod został dodany później.

Załóżmy przez chwilę, że jest to ok. Druga rzecz na jaką należy zwrócić uwagę to fakt użycia metody Any i zaraz potem użycie FirstOrDefault. Jest to zbyteczne, kod ten robi dwa razy to samo, wystarczy zastosować tylko FirstOrDefault.

Wróćmy teraz do przeszukiwania słownika na podstawie kodu. Przy pokazanej implementacji musimy w najgorszym wypadku sprawdzić wszystkie obiekty w słowniku co ma złożoność liniową. Przy dużej liczbie obiektów w słowniku i częstych odwołaniach do niego jest to nieefektywne. W takim wypadku należy wprowadzić drugi słownik, w którym kluczem będzie kod. W zależności od sytuacji będziemy używać jednego albo drugiego słownika. Jeśli nie znajdziemy w którymś słowniku szukanego obiektu to dodajemy go do OBU słówników.

Przeprowadziłem mały test obu rozwiązań. Najpierw napisałem trzy metody wyszukujące encje:
  • Znajdź na podstawie identyfikatora
  • Znajdź na podstawie kodu bez dodatkowego słownika
  • Znajdź na podstawie kodu z dodatkowym słownikiem
Początkowo słowniki są puste i generuję pewną liczbę N losowych identyfikatorów i kodów. Następnie znajduję te identyfikatory i kody korzystając z jednego słownika (Znajdź na podstawie identyfikatora + Znajdź na podstawie kodu bez dodatkowego słownika) oraz z dwóch słowników (Znajdź na podstawie identyfikatora + Znajdź na podstawie kodu z dodatkowym słownikiem). Oto wyniki:

Liczba N Liczba unikalnych identyfikatorów Czas (ms) dla dwóch słowników Czas (ms) dla jednego słownika
100 63 3 4
500 320 2 4
1000 639 2 6
5000 3169 2 96
10000 6326 4 370
50000 31579 14 9190

Czas mierzyłem dla trybu Release. Jak widać nawet dla małej liczby elementów dwa słowniki są szybsze i to pomimo konieczności zarządzania jednym słownikiem więcej. Dla dużej liczby elementów przewaga jest miażdżąca. Jest to kolejny przykład, jak ważne są dobrze dobrane struktury danych.

Na koniec zwrócę jeszcze uwagę, że dwa słowniki oznaczają większe zapotrzebowanie na pamięć. W moich eksperymentach dwa słowniki dla 10 tyś elementów zużyły ~0.5MB więcej pamięci niż 1 słownik, dla 50 tyś elementów ~1.3 MB więcej, a dla 100 tyś elementów ~3.3 MB więcej.

07/07/2013

TPL Dataflow + problem filozofów

Home

Jakiś czas temu na blogu Piotrka Zielińskiego przeczytałem o TPL Dataflow Library czyli o bibliotece dostarczającej komponentów ułatwiających komunikację (przekazywanie danych) w środowisku wielowątkowym. Temat mnie zaciekawił i postanowiłem trochę pobawić się z tą technologią. Na tapecie nie miałem żadnego "prawdziwego" projektu, w którym dałoby się wykorzystać nową zabawkę, postanowiłem więc wykonać ćwiczenie umysłowe i rozwiązać klasyczny problem pięciu filozofów z użyciem TPL Dataflow.

W moim rozwiązaniu każda pojedyncza pałeczka do jedzenia ryżu reprezentowana jest przez instancję klasy BufferBlock<T&gt gdzie T to w tym przypadku klasa Chopstick (klasa wydmuszka, nie zawiera żadnych właściwości ani metod). BufferedBlock<T>to nic innego jak kolejka FIFO, która może mieć wielu czytelników i wielu zapisujących.

Filozof potrzebuje jednak dwóch pałeczek aby rozpocząć jedzenie. Aby spełnić to wymaganie używam klasy JoinBlock<T,Z> gdzie T i Z do znowu klasa Chopstick. JoinBlock działa w ten sposób, ze monitoruje dwa źródła danych i jeśli w obu źródłach równocześnie są dane to grupuje je i wysyła do słuchacza. W tym przypadku JoinBlock czeka na dwie wolne pałeczki.
var chopsticks = new JoinBlock<Chopstick, Chopstick>(new GroupingDataflowBlockOptions { MaxNumberOfGroups = 1 });

_left.LinkTo(chopsticks.Target1);
_right.LinkTo(chopsticks.Target2);

_chopsticks = chopsticks.Receive();
Ustawienie właściwości MaxNumberOfGroups jest konieczne, aby blok odczytał tylko dwa komunikaty. Odłożenie pałeczek na stół jest natomiast równoważne z wysłaniem komunikatu (pałeczki) z powrotem do bufora tak, aby oczekujący na nie filozofowie mogli rozpocząć jedzenie.
_left.SendAsync(_chopsticks.Item1);
_right.SendAsync(_chopsticks.Item2);
Do tego, aby filozofowie mogli informować świat zewnętrzny o tym, co robią, również użyłem klasy BufferBlock<T>. Za każdym razem kiedy jeden z filozofów kończy/rozpoczyna jedzenie wysyła komunikat ze swoim aktualnym stanem. Ja napisałem prostą aplikację w WinForms, która nasłuchuje na te komunikaty i odpowiednio uaktualnia UI.
private readonly BufferBlock<PhilosopherState> _philosophersState = new BufferBlock<PhilosopherState>();
...
_philosophersState.LinkTo(new ActionBlock<PhilosopherState>(state => UpdateState(state)), new DataflowLinkOptions());
Każdy filozof modelowany jest przez instancję klasy Philosopher i działa w swoim własnym wątku. Co jakiś losowy czas decyduje, co robić dalej tj.: kontynuować myślenie/jedzenie czy rozpocząć myślenie/jedzenie. Kiedy zbierzemy to wszystko do kupy, otrzymamy następujący kod.

Pokaż/Ukryj kod klasy Philosopher
namespace PhilosopherProblemWithDataFlows
{
    public class Philosopher
    {
        private const int SleepTime = 100;

        private readonly int _index;
        private readonly BufferBlock<Chopstick> _left;
        private readonly BufferBlock<Chopstick> _right;
        private readonly BufferBlock<PhilosopherState> _philosophersState;

        private bool _goHome;
        private Tuple<Chopstick, Chopstick> _chopsticks;

        public Philosopher(int index, BufferBlock<Chopstick> left, BufferBlock<Chopstick> right, BufferBlock<PhilosopherState> philosophersState)
        {
            _index = index;
            _left = left;
            _right = right;
            _philosophersState = philosophersState;
        }

        public void TakeASeat()
        {
            var rand = new Random((int)DateTime.Now.Ticks);

            while (true)
            {
                if (_goHome)
                {
                    PutChopsticks();                
                    return;
                }

                if (rand.Next() % 2 == 0)
                    Eat();
                else
                    Think();

                Thread.Sleep((rand.Next(10) + 1) * SleepTime);
            }
        }

        public void GoHome()
        {
            _goHome = true;
        }

        private void Eat()
        {
            if (_chopsticks == null)
            {
                var chopsticks =
                    new JoinBlock<Chopstick, Chopstick >(new GroupingDataflowBlockOptions { MaxNumberOfGroups  = 1 });

                _left.LinkTo(chopsticks.Target1);
                _right.LinkTo(chopsticks.Target2);

                _chopsticks = chopsticks.Receive();
                chopsticks.Complete();
            }

            _philosophersState.SendAsync(new PhilosopherState { Index = _index,  IsEating = true });
        }

        private void Think()
        {
            PutChopsticks();

            _philosophersState.SendAsync(new PhilosopherState { Index = _index,  IsEating = false});
        }

        private void PutChopsticks()
        {
            if (_chopsticks != null)
            {
                _left.SendAsync(_chopsticks.Item1);
                _right.SendAsync(_chopsticks.Item2);
                _chopsticks = null;
            }
        }
    }

    public class Chopstick
    {
    }

    public class PhilosopherState
    {
        public int Index { get; set; }
        public bool IsEating { get; set; }
    }
}
Pokaż/Ukryj kod okna Win Forms
namespace PhilosopherProblemWithDataFlows
{
    public partial class Form1 : Form
    {
        private readonly Color EatingColor = Color.Red;
        private readonly Color ThinkingColor = Color.Green;

        private readonly List<Label> _stateLabels = new List<Label>();
        private readonly List<Philosopher> _philosophers = new List<Philosopher>();
        private readonly BufferBlock<PhilosopherState> _philosophersState = new BufferBlock<PhilosopherState>();

        public Form1()
        {
            InitializeComponent();
            Closing += (sender, args) =>
                {
                    _philosophersState.Complete();
                    _philosophers.ForEach(p => p.GoHome());
                };

            _stateLabels.Add(philosopher1);
            _stateLabels.Add(philosopher2);
            _stateLabels.Add(philosopher3);
            _stateLabels.Add(philosopher4);
            _stateLabels.Add(philosopher5);
            _stateLabels.ForEach(l => l.BackColor = ThinkingColor);
            
            Start();
        }

        private void Start()
        {
            _philosophersState.LinkTo(new ActionBlock<PhilosopherState>(state => UpdateState(state)), new DataflowLinkOptions());

            var chopsticks = new[]
                {
                    new BufferBlock<Chopstick>(),
                    new BufferBlock<Chopstick>(),
                    new BufferBlock<Chopstick>(),
                    new BufferBlock<Chopstick>(),
                    new BufferBlock<Chopstick>()
                };

            foreach (var ch in chopsticks)
                ch.Post(new Chopstick());

            for (var i = 0; i < 5; ++i)
                _philosophers.Add(new Philosopher(
                            i,
                            chopsticks[i],
                            chopsticks[(i + 1) % 5],
                            philosophersState));

            for (var i = 0; i < 5; ++i)
            {
                var th = new Thread(_philosophers[i].TakeASeat);
                th.Start();
            }
        }

        private void UpdateState(PhilosopherState state)
        {
            var label = _stateLabels[state.Index];
            label.Invoke((MethodInvoker)delegate { label.BackColor = state.IsEating ? EatingColor : ThinkingColor; });
        }
    }
}

Kod designer'a pominąłem bo jest trywialny i zawiera tylko 5 etykiet o nazwach philosopher1, philosopher2 itd.

Na koniec mała zagadka. Moja implementacja zawiera pewne uproszczenie oryginalnego problemu 5 ucztujących filozofów. Jakie?

23/03/2013

Migracja bazy danych w EF

Home

Już dawno temu pisałem o zastosowaniu RavenDB w swoim projekcie. Początkowo byłem zadowolony z tego wyboru ale jakiś czas temu zdecydowałem się przejść na Entity Framework + SQLCe. Czemu? To temat ta cały post, tak w skrócie to zirytowało mnie to, że RavenDB stara się być mądrzejszy od programisty oraz to jak trudno osiągnąć w nim niektóre rzeczy. Nie twierdzę, że RavenDB jest zły, ale tak jak inne dokumentowe bazy danych nie do wszystkiego się nadaje.

Wracając do tematu, przechodząc do EF zdecydowałem się wykorzystać podejście code first. Wcześniej tego nie próbowałem i muszę powiedzieć, że byłem bardzo zadowolony, migracja odbyła się w miarę bezboleśnie. Swoją drogą zaprocentowała początkowa decyzja aby ukryć technologię dostępu do danych za dobrze określonym interfejsem. Dzięki temu zmiany musiałem wprowadzić w niewielu miejscach. Nie ma jednak róży bez końców. Kiedy po jakimś czasie chciałem dodać nową właściwość do swoich encji otrzymywałem błąd:

The model backing the context has changed since the database was created...

Za pierwszym razem poradziłem sobie z tym tworząc bazę danych od początku i importując dane ale na dłuższą metę byłoby to uciążliwe. Zacząłem kombinować nad rozwiązaniem, które zmieniłoby schemat bazy danych przed użyciem EF. Wtedy natknąłem się na artykuł opisujący to zagadnienie i był to strzał w dziesiątkę. Oto krótki opis co zrobiłem:.
  • Dodałem nową właściwość do encji.
  • Zmodyfikowałem logikę biznesową.
  • Uruchomiłem Package Manager Console.
  • Jako Default project wybrałem projekt, z klasę dziedziczącą po DbContext. Jeśli takich klas jest więcej zostanie zgłoszony błąd.
  • Wydałem polecenie Enable-Migrations.
  • Do projektu został dodany katalog Migrations, a w nim klasa Configuration.
  • Wydałem polecenie Add-Migration tj. Add-Migration AddColumn.
  • W projekcie została utworzona klasa AddColumn dziedzicząca po DbMigration. Dla mnie interesujące była metoda Up, w której umieściłem kod odpowiedzialny za uaktualnienie bazy danych. Wyglądało to w następujący sposób:

    public override void Up()
    {
       AddColumn("TranslationEntities", "Translation2", c => c.String(true, maxLength: 4000, storeType: "nvarchar"));
    }
    

    Metoda AddColumn to metoda klasy DbMigration. Jest ich dużo więcej np.: AddForeignKey, CreateIndex czy RenameColumn.
  • Na koniec użyłem klasy MigrateDatabaseToLatestVersion w celu zainicjowania bazy danych:

    Database.SetInitializer(new MigrateDatabaseToLatestVersion<ExpressionsDataContext, Configuration>());

  • Przy kolejnym uruchomieniu aplikacji zadziały się dwie rzeczy. Do tabelki TranslationEntities została dodana nowa kolumna oraz utworzona została nowa tabela __MigrationHistory. Dzięki tej nowej tabelce EF będzie śledził historię wprowadzanych zmian i nie uruchomi tej samej migracji więcej niż raz.
To bardzo prosty przykład. Jestem ciekawy jak ta funkcjonalność spisuje się w bardziej skomplikowanych scenariuszach. Czy macie jakieś doświadczenia?