Thursday, June 14, 2007
Here's the code for my last post on Annotations - I tidied up a few things up (it's still very basic but it does work) there's a single test fixture to give you a guide for usage... so things like:

[Test]
public void QueryStoreForClassAnnotationsWithCertainKey()
{
   
ClassA target1 = new ClassA();
    ClassA target2 = new ClassA();
    ClassA target3 = new ClassA();

    target1.Annotate(Description =>
"class number 1");
    target2.Annotate(Description => "class number 2");
    target3.Annotate(Parsed =>
true);

    var results = AnnotationStore.Classes
      .Where(a => a.HasKey(
"Description"))
      .ToList();

    Assert
.AreEqual(2, results.Count);
}

And also the equivalent thing is possible for members... though I suspect annotating members isn't all that useful in most cases...

[Test]
public void QueryStoreForMemberAnnotations()
{
    ClassA target1 = new ClassA();
    ClassA target2 = new ClassA();
    ClassA target3 = new ClassA();

    target1.Annotate(() => target1.FirstName, CamelCase => true); // annotating a property
    target1.Annotate(() => target1.Field, Ignored => true); // annotating a field
    target2.Annotate(() => target2.Execute(), Parsed => true); // annotating a method

    target3.Annotate(Parsed =>
true);

    var results = AnnotationStore.Members
      .Where(p => p.HasKey(
"CamelCase"))
      .ToList();

    Assert.AreEqual(1, results.Count);
}


 |  | 
posted @ Thursday, June 14, 2007 4:06:12 AM (New Zealand Standard Time, UTC+12:00)    Comments [1] | Trackback |
I've been under whelmed with GoogleGears & GoogleReader as a combination (though it has enabled search capabilities for the last 2000 posts to GoogleReader which is a god send)...

But what I was thinking of that would be particularly useful in offline mode, a wiki... I wonder if it'll ever happen?

posted @ Thursday, June 14, 2007 2:30:58 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |

So I've been mulling some ideas over after the whole abusing lambdas for Hash table construction (here and here) ... and after reading a post on Jb Evain's blog I decided to create a little bit of code for doing annotations... so given a class say:

public class ClassA
{
    public int Id { get; set; }
    public string Name { get; set; }
}

You can then do this kind of thing (assuming you've added the apropriate namespace where the Annotations static class resides in)

[Test]
public void AnnotateClass()
{
    ClassA classA = new ClassA();
    classA.Annotate(IsValid =>
false);
    classA.Annotate(MapsToTable =>
"TblClassA", Key => "Id");
    classA.Annotate(Roles =>
new [] {"Administrator", "User"});

    Assert.IsFalse(classA.Annotation<bool>("IsValid"));
    Assert.AreEqual("TblClassA", classA.Annotation<string>("MapsToTable"));
    Assert.AreEqual("Id", classA.Annotation<string>("Key"));
}

Or, perhaps you want to attach some annotations to a specific property... no problem!

[Test]
public void AnnotateProperty()
{
    ClassA classA = new ClassA();
    classA.Annotate(() => classA.Name, CanBeNull =>
true);
    bool canBeNull = classA.Annotation<bool>(() => classA.Name, "CanBeNull");
    Assert.AreEqual(true, canBeNull);
}

Under the hood the values are stored against a dictionary where the keys (in this case the instance of classA) are weak referenced... so once classA is garbage collected the entries in the dictionary will also dissapear in time (next time any method touches the dictionary).

The nice thing is obviously you can directly interogate the Annotations static class itself with a query expression to say find all objects with a certain annotation.

 |  | 
posted @ Wednesday, June 13, 2007 10:32:16 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
 Tuesday, June 12, 2007

So, I got a comment on the last post about hashes from lambdas (from Andrey Shchekin)... It pointed out the fact that you don't need to use expressions at all... which hilights an observation that I hadn't made myself - such that the lambda parameter names are available in the generated delegate... which of course makes perfect sense!

So given:

Func<string, T> func = Name => "Value";

You can get the lambda parameter "Name" from the function delegate by calling:

func.Method.GetParameters()[0].Name (would return "Name")

Here's the revised Hash method from Andrey:

public Dictionary<string, T> Hash<T>(params Func<string, T>[] args)
where T : class
{
   
var items = new Dictionary<string, T>();
   
foreach (var func in args)
    {
       
var item = func(null);
        items.Add(func.Method.GetParameters()[0].Name, item);
    }
   
return items;
}

very elegant and simple :)

He even did some stats, which I suspect are probably a lot more accurate then my inital observations:

For 10000 consecutive calls:

WithAdd 10.0144ms
WithLambdas 9713.968ms
WithLambdasConstantsOnly 240.3456ms
WithDelegates 30.0432ms

Now what about multiple parameters... so far I can't think of any uses I would have for it... perhaps a 2 level configuration dictionary?

[Test]
public void HashTwoLevelDict()
{
   
Dictionary<string, Dictionary<string, object>> config = this.Hash<object>(
     (Connection, DriverClass) =>
typeof(SqlClientDriver),
     (Dialect, DialectClass) =>
typeof(MsSql2000Dialect),
     (Connection, Provider) =>
typeof(DriverConnectionProvider),
     (Connection, ConnectionString) =>
"Data Source=.;Initial Catalog=test;Integrated Security=SSPI");

    Assert.AreEqual(typeof(SqlClientDriver), config["Connection"]["DriverClass"]);
}

Who knows... I look forward to seeing how Lambdas get used and abused for non-functional programming tasks :)
 |  | 
posted @ Tuesday, June 12, 2007 1:22:21 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Monday, June 11, 2007
So first off... I'm surely not the first person to see the resemblance between a lambda expression and a hash table declaration in Ruby... so I had a go at populating a dictionary using lambda's... so given this:

[Test]
public void Evaluate()
{
    Dictionary<string, string> items = Hash(Name => "alex", Age => "10", Height => "20");
    Assert.AreEqual("alex", items["Name"]);
    Assert.AreEqual("10", items["Age"]);
    Assert.AreEqual("20", items["Height"]);
}

I got my desired result pretty quickly...

public Dictionary<string, T> Hash<T>(params Expression<Func<string, T>>[] args)
where T: class
{
    Dictionary<string, T> items = new Dictionary<string, T>();
    foreach (Expression<Func<string, T>> expression in args)
    {
       ConstantExpression itemValueExpression = expression.Body as ConstantExpression;
       if (itemValueExpression == null
       throw new InvalidCastException("The body of the expression must be of type ConstantExpression");
        T item = itemValueExpression.Value
as T;
        items.Add(expression.Parameters[0].Name, item);
    }
    return items;
}

But, then I tried this...

[Test]
public void EvaluateForObjects()
{
   
Dictionary<string, object> items = Hash<object>(Name => "alex", TargetType => typeof(Uri), Id => 10);
   
Assert.AreEqual(10, items["Id"]);
}

Which fails, the last key/value pair (Id => 10) isn't represented as a ConstantExpression, so to support it (and other eventualities) I modified my code a smidge...

public Dictionary<string, T> Hash<T>(params Expression<Func<string, T>>[] args)
where T: class
{
   
Dictionary<string, T> items = new Dictionary<string, T>();
   
foreach (Expression<Func<string, T>> expression in args)
   
{
       
ConstantExpression constantExpression = expression.Body as ConstantExpression;
        T item =
null;
       
if (constantExpression != null)
        {
          item = constantExpression.Value
as T;
        }
       
else
       
{
           
item = Expression.Lambda<Func<T>>(expression.Body).Compile()();
       
}
        items.Add(expression.Parameters[0].Name, item);
    }
    return items;
}

Now... let's compare performance to say, adding the values using the Add method... so... for a million consecutive executions (in milliseconds) a quick test yielded these results...

Execution # Using 'Hash' Using Dictionary.Add()
1 9718 1268
2 9588 1310
3 9636 1494

Which I suspect tells me nothing more then the fact that the "Hash" style initialization is a lot slower, but not slow enough to completely discourage me.


Edit: There seems to be a bit of interest in this lately, so don't forget to take a look at the other related posts if you found this interesting.

 |  | 
posted @ Monday, June 11, 2007 9:32:15 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
 Wednesday, May 30, 2007
I've been getting a few questions about different aspects of the container tutorials series I posted a while back - while the series is not finished, neither is it forgotten, I've collated information regarding the series into a topic on my wiki and I'll keep this up to date until I've finished the series off.

I also notice Sam Gentile has posted that he's taking the plunge into learning about castle's Windsor container... good to hear :)


 |  | 
posted @ Wednesday, May 30, 2007 5:30:43 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Monday, May 28, 2007

It's been a long time since I've really felt "pleased" by the results of overclocking... probably back in the days of the 300A if truth be told, which is in the long long ago ;o) ... and for the last year I've been mostly using a laptop, and having really kept track of desktop tech.

... So I have to admit to being very pleasantly surprised when I built myself a Core Duo machine (to be used while my Laptop is getting a labotomy) with a bottom of the barrel 4300 processor and then proceeded to overclock it from 1800mhz to 3042mhz ... that's a serious leap in performance :) very pleasing... and I still haven't hit the ceiling which is even more pleasing, I just had to stop fiddling and get on with doing some actual work.

 

 

 

posted @ Monday, May 28, 2007 5:46:32 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Wednesday, May 09, 2007
More parts in the container tutorial series are on the way, I've just been a little busy these last few days.

However I had a discussion with someone about decorators this week - they eluded to them being too hard to "create" and maintain, and that opportunities to get them wrong abound (manually writing the code to call all the members of the inner service) - I was a little astounded that they didn't know how to do this using ReSharper.

So heres a quick 1 minute tutorial for those that don't know, first an interface.

public interface IBondService

{

    void Smoke50Cigarettes();

    void RegisterEnemy(string name);

    void GetOfBed();

    bool GunLoaded();       

}


Now let's write the start of our decorator.

public class BondService : IBondService

{

    private readonly IBondService _innerService;

 

    public BondService(IBondService innerService)

    {

        _innerService = innerService;

    }

}


And then generate the rest... by going to: ReSharper ->Code->Generate...->Delegating Members

Or just type Alt-insert (if your using the default key bindings) and select "Delegating Members".

At that point select the only option, the inner service.

delegate_members_1.png

And then select all the members to delegate for.

delegate_members_2.png

And then we get the results... joy

public class BondService : IBondService

{

    private readonly IBondService _innerService;

 

    public BondService(IBondService innerService)

    {

        _innerService = innerService;

    }

 

    public void Smoke50Cigarettes()

    {

        _innerService.Smoke50Cigarettes();

    }

 

    public void RegisterEnemy(string name)

    {

        _innerService.RegisterEnemy(name);

    }

 

    public void GetOfBed()

    {

        _innerService.GetOfBed();

    }

 

    public bool GunLoaded()

    {

        return _innerService.GunLoaded();

    }

}


posted @ Wednesday, May 09, 2007 3:11:45 AM (New Zealand Standard Time, UTC+12:00)    Comments [4] | Trackback |
 Tuesday, May 08, 2007
So I quite like Family.Show as an end to end solution of WPF goes... but I think what's been more fascinating is seeing how my (beautiful) Financee is finding it as a working product.

So she's a big genealogy zealot - and for the first time when saying "hey have a look at this" for some random piece of tech I could see here interest was piqued, so we click-once'd it onto her machine and she's been playing around with it for the last day or so - having loaded around 300 people into it so far.

First off the good - it's pretty, and very fluent - you can see immediately who's being edited, current vs. past relationships, dead vs. alive (hollow people are dead... ) And it performs nicely... 200+ vector "people" on screen and the machines not sweating a bit.  

Surprisingly it's also pretty quick for data entry, something I had my doubts about when first looking at the application vs. something a little more traditional - after about 5 minutes of experimentation she was an expert.

Second the bugs... well the main one is that certain characters in a name like a double quote causes the "stories" data screen to crash upon saving...  And every now and then it just flakes out completely... I might throw some logging into and see just what's going on, it doesn't even let you get a stack trace *erk*.

Interaction - well here's where she's getting pissed with it and I'll probably need to enhance it a little - and it's all to do with relationships...  there doesn't appear to be any way to establish a relationship between two people once their added to the tree... a pretty big oversight - they expect you to add all relationships by adding a brother/mother/father/sister/spouse/child to the person currently being edited, but that means you cant actually implement something like:
  • Joe marries Jane
  • Bob marries Martha
  • Jane & Bob die
  • Joe marries Martha
A big problem during times of war because it was not uncommon for widows to marry the brother of their dead husband.  This seems like a big oversight (though it is just a tech demo).

Interesting though, and this sample is definitely the best WPF app with source code I've had to play/learn from... great stuff Vertigo.

posted @ Monday, May 07, 2007 9:22:38 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Thursday, May 03, 2007
So looking at Astoria very briefly today ... a good starting point is probably Alex James blog and all the linked posts - and so far I'm left with a "so what" attitude to the technology releases so far (but it is very early days).

I feel like what's being presented is something I could cobble together using Dream and ActiveRecord/NHibernate or Base4 with a couple of weeks work at best... I'm probably being a little optimistic though ;o) Devil is always in the detail... but what's in the wild so far hasn't made me sit up and take notice, I hope the next couple of drops will though.

However in the mean time, what does interest me:
  • Standardization of a query scheme... so far I've only seen examples of search/get queries.. I'm particularly interested in any update related queries... this is where the opportunities for doing evil live, and where community input will be vital I think.
  • How does WebDAV fit into the Astoria picture at the moment?
  • Astoria SaaS ... I find the idea of being able to design and provision REST'ful stores on the web (with my own schema) quite intriguing.
    • That said - I'm not sure what I'd do with it, but I still want it ;o)
    • And thinking out loud, but besides the obvious uses for web/ajax/flash/silverlight fraternity *yawn* - could this kind of thing actually give new life to some desktop based applications - It could certainly smarten them up a bit, so that using the same application on multiple machines (i.e. work/home) could optionally give you the same experience.
 |  |  | 
posted @ Wednesday, May 02, 2007 8:12:14 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation