Sunday, May 15, 2011

Expressionistic copying

Recently I had the need of cloning a number of object, traditionally you’d have to use reflection based techniques if you wanted a generic solution, (unless you go really hardcore with Reflection.Emit)

The sample code below only accounts for public properties, but in many cases that isn’t enough.

Given the performance implications of using reflection, and the fact that you are allowed to include blocks in expressions in .NET 4 I figured I’d do a small experiment and micro-benchmark comparing these two approaches:

I have an entity I want to copy like so

public class Entity
{
public int Foo { get; set; }
public string Bar { get; set; }
public string Baz { get; set; }
public int Foo2 { get; set; }
public string Bar2 { get; set; }
public string Baz2 { get; set; }
public int Foo3 { get; set; }
public string Bar3 { get; set; }
public string Baz3 { get; set; }
}

I implemented reflection based copy like so (with some room for optimizations):



public class ReflectionObjectCopier : IObjectCopier
{
#region IObjectCopier Members

public void Copy<T>(T fromObj, T toObj)
{
var properties = from prop in fromObj.GetType().GetProperties(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.FlattenHierarchy)
where prop.CanRead && prop.CanWrite
select prop;
foreach (PropertyInfo pi in properties)
{
pi.SetValue(toObj, pi.GetValue(fromObj, null), null);
}
}

#endregion
}


When using this copying 10 000 objects takes 250ms or so.



However, if I create an expression that performs the copying directly it only takes 10ms (with subsequent testruns only taking 4, when reusing the cached expression). That is a pretty decent saving if you ask me.



public class ExpressionObjectCopier : IObjectCopier
{
Dictionary<Type, object> cache = new Dictionary<Type, object>();

Action<T,T> CreateCopier<T>()
{
ParameterExpression fromParam = Expression.Parameter(typeof(T), "from");
ParameterExpression toParam = Expression.Parameter(typeof(T), "to");

LambdaExpression exp = Expression.Lambda(typeof(Action<T, T>),
Expression.Block(
from prop in typeof(T).GetProperties(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.FlattenHierarchy)
where prop.CanRead && prop.CanWrite
select Expression.Assign(Expression.Property(toParam, prop),
Expression.Property(fromParam, prop))
),
fromParam,
toParam);

Action<T, T> copier = (Action<T, T>)exp.Compile();
cache[typeof(T)] = copier;
return copier;
}

#region IObjectCopier Members

public void Copy<T>(T fromObj, T toObj)
{
object action;
Action<T,T> copier;
if (!cache.TryGetValue(fromObj.GetType(), out action))
{
copier = CreateCopier<T>();
}
else
{
copier = (Action<T, T>)action;
}


copier(fromObj, toObj);
}

#endregion
}


The above code obviously isn’t production quality…

Tuesday, November 02, 2010

Timeline – or restyling controls

One nice thing with WPF that is slightly different is that the controls are lookless. This means that you can re-style or apply a different template altogether if the behavior of a standard control is what you want, but the looks are not.

A real world example: At work we recently needed to show a list of items with associated timestamps, in a way so that the time differences between them are easily determined at a glance.

Thanks to the lookless controls of WPF I was able to solve this simply by using a ListBox with re-templated ListBoxItems giving the following result:

image

The style is defined as follows:

        <Style TargetType="ListBoxItem" x:Key="TimelineStyle">
            <
Setter Property="SnapsToDevicePixels" Value="true"/>
            <
Setter Property="OverridesDefaultStyle" Value="true"/>
            <
Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <
Setter Property="Template">
                <
Setter.Value>
                    <
ControlTemplate TargetType="ListBoxItem">
                        <
StackPanel Orientation="Vertical"> <Border
                           
Name="Border"
                           
Padding="2"
                           
CornerRadius="2"
                           
BorderThickness="2"
                           
SnapsToDevicePixels="true">
                                <
ContentPresenter />
                            </
Border>
                            <
Grid>
                                <
Rectangle Width="2" Stroke="LightBlue"
                                          
Height="{Binding TimeToNext, Converter={StaticResource HeightConverter}}"
                                          
VerticalAlignment="Center"
                                          
HorizontalAlignment="Center"/>
                                <
TextBlock Text="{Binding TimeToNext, Converter={StaticResource DurationConverter}}"
                                          
Background="White"
                                          
VerticalAlignment="Center"
                                          
HorizontalAlignment="Center"
                                          
FontSize="8"
                                          
Foreground="Gray"/>
                            </
Grid>
                        </
StackPanel>
                        <
ControlTemplate.Triggers>
                            <
Trigger Property="IsSelected"
                                    
Value="true">
                                <
Setter TargetName="Border"
                                       
Property="BorderBrush"
                                       
Value="Blue"/>
                            </
Trigger>
                        </
ControlTemplate.Triggers>
                    </
ControlTemplate>
                </
Setter.Value>
            </
Setter>
        </
Style>

and and the listbox uses the style like this:

<ListBox ItemsSource="{Binding DataItems}" ItemContainerStyle="{StaticResource TimelineStyle}" />



The style uses two converters, but those should be fairly trivial.



Setting FocusVisualStyle to {x:Null} is done to hide the indication of keyboard focus, as unless it is fixed properly, will be more confusing than helpful. Fixing it properly is left as an exercise for the reader.

Saturday, February 06, 2010

MCTS

Today I passed the second certification exam 70-502. So now I’m officially a Microsoft Certified Technology Specialist: .NET Framework 3.5, Windows Presentation Foundation Applications.

Monday, February 01, 2010

Nullable<T> and IFormattable

If you ever tried to format a nullable type you would soon realize that you cannot directly as Nullable<T> does not implement IFormattable and thus you only have object.ToString() available.

This is easily fixed using an extension method:

public static class NullableExtensions
{
public static string ToString<T>(
this Nullable<T> nullable,
string format,
IFormatProvider formatProvider)
where T : struct, IFormattable
{
if (!nullable.HasValue) return string.Empty;
T notNull = nullable.Value;
return notNull.ToString(format, formatProvider);
}
}


and you can use it e.g. like so:



            DateTime? foo = null;
...
foo.ToString("t", CultureInfo.CurrentCulture);

Thursday, January 21, 2010

WPF project building inside of Visual Studio but not with MSBuild/TFSBuild

At work, I recently run into a strange build error when building from MSBuild and TFSBuild while the same solution built inside of Visual Studio 2008 just fine.

The error message was:

error MC3015: The attached property '?' is not defined on '?' or one of its base classes.

(obviously with real names instead of the questionmarks)

Feeding the above into google provided the following solution to the issue:

One of the differences between building in VS and command line is that a WPF build in VS defaults to

<AlwaysCompileMarkupFilesInSeparateDomain>true</AlwaysCompileMarkupFilesInSeparateDomain>.
Outside of VS, the default is false.

(Answer by Rob Relyea)

Adding that to the relevant .csproj made the project build successfully.

Monday, November 30, 2009

MeasureUp FAIL

I’m currently studying for the 70-536 on my way towards MCTS certification.

I have the self-paced training kit and thought I’d do the Training Kit Exam Prep “Powered by MeasureUp”

Things go without technical issues until I get to scoring.

Then I am greeted with:

---------------------------
Application Message
---------------------------
An unanticipated error has occurred in the application.InsertScoreHistory

[Microsoft OLE DB Provider for ODBC Drivers] [3604] [Microsoft][ODBC Microsoft Access Driver] Syntax error in date in query expression '#30.11.2009 21:51:40#'.
---------------------------
OK   Cancel  
---------------------------

Trying to review a particular answer fails with:

---------------------------
Application Message
---------------------------
An unanticipated error has occurred in the application.GoToQuestionSelected

[Microsoft.VisualBasic] [13] Conversion from string "7." to type 'Short' is not valid.
---------------------------
OK   Cancel  
---------------------------

I then eventually end up at the FAQ page at MeasureUp and find

I'm receiving Error: Mismatch 13.
In order for tests to display correctly, your computer's regional settings should be set to English (United States).

In the control panel, please double click on the icon labeled Regional Settings. Please choose English (United States), and click the box that says "use default properties for this input locale."

Alternatively, in the regional settings, look at the Currency tab. If it is set the decimal symbol to . (dot) instead of , (coma), that may be enough to get it working properly.

If the trouble persists, try setting the keyboard language layout to English (United States). In the control panel, double click on the icon labeled "Keyboard". Then click on the tab labeled input locales. Select the Add button. And then choose English (United States) as the input locale.

W T F !?!

It’s kinda ironic that one of the skills measured is “Implementing globalization, … in a .NET Framework application”

What’s even more tragic is that if I actually DO change to en-us, trying to start a new test fails, this time with:

---------------------------
Application Message
---------------------------
An unanticipated error has occurred in the application.PreviousSessionTestRecord

[Microsoft.VisualBasic] [13] Conversion from string "30.11.2009 21:58:26" to type 'Date' is not valid.
---------------------------
OK   Cancel  
---------------------------

Tuesday, November 10, 2009

roleProvider app.config parsing troubles

I recently had the pleasure of trying to get our RC out the door, while doing that we realized that for whatever reason, Microsoft seems to use a non-standard parser for the app.config file.

Basically this does not work:

<system.web>
  <
roleManager defaultProvider="MyCustomProvider" enabled="true">
    <
providers>
      <
clear></clear>
      <
add name="MyCustomProvider" type="Namespace.MyCustomProvider, MyAssembly"/>
    </
providers>
  </
roleManager>
</
system.web>

While this does:

<system.web>
  <
roleManager defaultProvider="MyCustomProvider" enabled="true">
    <
providers>
      <
clear/>
      <
add name="MyCustomProvider" type="Namespace.MyCustomProvider, MyAssembly"/>
    </
providers>
  </
roleManager>
</
system.web>

Of course, the well known commercial installer making tool we are using insists of creating the former… :(

A workaround is to throw the file through an identity XSLT transform in a custom tool / custom action run after custom actions from said vendor have done their job.

Oh, the bug reported on connect is already closed as Won’t Fix

Wednesday, September 02, 2009

Windows Live Movie Maker - FAIL

As I wanted to edit some movies, and Windows 7 no longer includes Windows Movie Maker I had to give Windows Live Movie Maker a try, as based on the name you’d assume it does something similar?

Turns out I was wrong. This application seems to be geared towards dropping a number of photos and creating a “movie” and not actually editing movies.

While you can import video from a DV camera, it does not split the imported video into scenes, instead it chops it into pieces, the size of which you can determine by dragging a slider !?! And to make matters worse, it does not bother to extract thumbnails from the individual pieces but instead uses what seems to be the first frame of the entire movie. Good luck finding the pieces you need.

Of course, the timeline also seemed unnecessary to include …

Time to look for a Video editor, Windows Live Movie Maker is not one.

</rant>

Tuesday, March 03, 2009

Generating GUIDs

This may seem trivial but here we go:

I recently created an installer with WIX and obviously had to create a number of GUIDs along the way. While there is a "Create GUID" option in the Tools menu it has a number of drawbacks:

  • Clicking around a UI with a mouse is not the most efficient thing in the world
  • There is not an immediately suitable format available, registry format is closest, but braces need to be removed and the rest uppercased

The obvious? solution to this problem is to create a macro like the following:

Public Sub CreateWixGuid()
Dim g As Guid = Guid.NewGuid()
Dim textSelection As EnvDTE.TextSelection

textSelection = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection)
textSelection.Text = g.ToString("D").ToUpper()
End Sub


and assign a keyboard shortcut to it (I chose Ctrl+G,Ctrl+G), and voilà a GUID in the correct format is generated and inserted.



 



 

Tuesday, November 11, 2008

How to not do validation

Yesterday when I was trying to do some online shopping I the e-commerce system in use perfomed input validation in a slightly suboptimal way. Here is what happened:

  • To be able check out the stuff in my shopping basket I had to create an account.
  • To create an account I had to enter username, password and address.
  • Go to checkout
  • Confirm to use the just entered address as the shipping address
  • On the following page where the pay button should be there's this small note "The city is not long enough"  WTF!?!
  • Try again with the city name in the other language as it is longer
  • Same story "The city is not long enough" ...
  • Only when changing the primary address the order goes through

A validation rule stating that the city cannot be just three letters are just plain stupid, secondly if there is a need to use stupid validation rules, then do the validation when the data is entered and not when it is used ...

This comic comes to mind.

Saturday, November 08, 2008

Debugging WPF databinding issues

Lately due to switching teams and project I've been doing much more WPF than before. I cannot say I have fully mastered the learning curve yet but I'm getting better and it is an interesting journey.

Occasionally the data bindings does not work as expected and then it is nice to get more information about them in order to figure out what went wrong.

The following is useful when you want to know why a particular binding is misbehaving (or rather you want to know where you screwed up...)

xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"



ItemsSource="{Binding <snip>, diagnostics:PresentationTraceSources.TraceLevel=High}"


The above information and MUCH more is presented by Beatriz Stollnitz



(This post is also a 'reminder to self')

Monday, November 03, 2008

C# quiz 9/?

Consider the following:

Guid globallyUnique1 = new Guid();
Guid globallyUnique2 = new Guid();
if (globallyUnique1 == globallyUnique2)
{
MessageBox.Show("This cannot be");
}
else
{
MessageBox.Show("Everything is well");
}

What is shown? Why?

Wednesday, October 15, 2008

Sandcastle to dead tree format woes

For reasons partially unknown to me, I was tasked with converting Sandcastle generated API documentation to dead tree format.

The best way seems to be feeding some magic XSLT to Sandcastle that would that would directly create PDF via XSL-FO or DocBook or whatever. However, I haven't been able to find such a thing and I'm not ready to put down that kind of work to create it myself at this point.

Another option I pursued was to print the CHM to XPS/PDF but this has its own cons. Firstly directly printing from CHM viewer strips CSS rendering ugliness. This is correctable by finding the correct html file from %TEMP% and a little search/replace magic and providing the stylesheets and images.

Having gotten this far I found out that the stylesheet needs to use something else but relative font size to keep the text legible.

Now as if this wasn't enough the browser or at least the PDF/XPS "printer" chokes on the sheer amount of input, still not finished after N hours, and this just for the documentation of a smallish test assembly. :(

This does not look feasible at this point.

Bright ideas appreciated!

Thursday, April 03, 2008

C# quiz 8/?

Now it's time for some one regarding serialization:

Given this serializable class:

    [Serializable]
public class Victim {
public static int InstanceCount;
public int Data { get; set; }

public Victim() {
InstanceCount++;
Data = 2;
}
}

and the following test code:

    class Program {
static void Main(string[] args) {
Victim v = new Victim();
v.Data = 3;
BinaryFormatter serial = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
serial.Serialize(ms, v);
ms.Seek(0, SeekOrigin.Begin);
v = (Victim)serial.Deserialize(ms);
Console.WriteLine("Data {0}", v.Data);
Console.WriteLine("Instances {0}", Victim.InstanceCount);
}
}

What is the output, and why?

C# quiz 7/?

If we compile the following code to a dll, for example using the following command line:

csc.exe /t:library Library.cs

namespace Library {
public class Library {
public const int FOO = 1;
public static readonly int BAR = 2;
}
}

And refer those in our test program:

    class Program {
static void Main(string[] args) {
Console.WriteLine(Library.Library.FOO);
Console.WriteLine(Library.Library.BAR);
}
}

Now, if we change FOO to 10 and BAR to 12 and recompile Library.dll without recompiling the test program, what is the output when we run the test program?

C# quiz: 6/?

Consider the following:

    class Test {
private int m_foo;
public int Foo {
get { return m_foo; }
}
public int set_Foo(int value) {
m_foo = value;
}
}

What happens when you compile, and why?


Wednesday, April 02, 2008

C# quiz: 5/?

Consider a console application with the following Main:

        static void Main(string[] args) {
System.Threading.Timer t = new Timer(dummy =>
{
Console.WriteLine("In callback: " + DateTime.Now);
GC.Collect();

}, null, 0, 1000);

Console.ReadLine();
t = null;
}

What does the code do? Does it matter if it is compiled Debug or Release, if so, why?


(To give proper credit where credit is due, this example is heavily inspired by CLR via C# by Jeffrey Richter)


C# quiz: 4/?

Given the following code:

    internal class Test {
public int Foo { get; set; }
public int Bar { get; set; }

#if CUSTOM
public override int GetHashCode() {
return Foo.GetHashCode() ^ Bar.GetHashCode();
}

public override bool Equals(object obj) {
if (object.ReferenceEquals(obj, null)) return false;
Test t = obj as Test;
if (t != default(Test)) {
return (Foo == t.Foo) && (Bar == t.Bar);
}
return false;
}
#endif
}

and the following test code:

            Dictionary<Test, string> dict = new Dictionary<Test, string>();
Test foo = new Test { Foo = 1, Bar = 2 };
dict[foo] = "Hello World";
foo.Bar = 42;
if (dict.ContainsKey(foo)) {
Console.WriteLine("it's there");
} else {
Console.WriteLine("it's not");
}

Answer the following questions:



  1. With CUSTOM not defined, what does the test code print?

  2. If CUSTOM is defined, does it change the outcome?

  3. What if Test is changed to a struct and CUSTOM is not defined, what is the output?

  4. If Test is a struct and CUSTOM is defined, what happens?

Tuesday, April 01, 2008

C# quiz: 3/?

Consider the following class:

    internal class Test {

public int Code { get; set; }

public static bool operator ==(Test lhs, Test rhs) {
if (object.ReferenceEquals(lhs, rhs)) return true;
if (lhs == null || rhs == null) {
return false;
} else {
return lhs.Code == rhs.Code;
}
}

public static bool operator != (Test lhs, Test rhs) {
return !(lhs == rhs);
}
}

What is the outcome of the following test code, and why?

            Test test1 = new Test { Code = 42 };
Test test2 = new Test { Code = 42 };
if (test1 != test2) {
Console.WriteLine("different");
} else {
Console.WriteLine("equals");
}

Monday, March 31, 2008

C# quiz: 2/?

Continuing on the series of C# and/or .NET Framework short questions:

        private void Foo(List<int> bar) {
bar = new List<int>();
// ...
}

With the method above and the code below:

        List<int> bar = null;
Foo(bar);
if (bar != null) {
Console.WriteLine("populated");
} else {
Console.WriteLine("still null");
}
If or else ?

EDIT: fixed typo in code sample.