Marc’s Lib goes mainstream

September 29, 2006 on 10:00 pm | In .NET Coding | No Comments

http://www.codeplex.com/Wiki/View.aspx?ProjectName=Dynamic

Sweet! Awe, it’s all grown up now!

Cool test for between-ness

September 24, 2006 on 11:43 pm | In .NET Coding | 3 Comments

I traditionally hated testing for between-ness, because I had to order the endpoints. Like to determine if x was between y and z I had to make sure that y and z were arranged in the right order and then do if x < z and x > y then return true. Well I found a better way now that allows me not to care:


// tests to see if x is between y and z (inclusively)
public bool IsBetweenIncl(IComparable x, IComparable y, IComparable z)
{
  int a = x.CompareTo(y);
  int b = x.CompareTo(z);
 
  if ( (a >= 0) != (b >= 0))
     return true;
 
  return false;
}
 
// tests to see if x is between y and z (exclusively)
public bool IsBetweenExcl(IComparable x, IComparable y, IComparable z)
{
  int a = x.CompareTo(y);
  int b = x.CompareTo(z);
 
  if ((a > 0) != (b > 0) )
     return true;
 
  return false;
}

Not earth shatterning, but it’s things like this that keep me sane when I’m writing the compiler. Yes I know there are more terse ways of writing that same stuff, but this is an illustration.

Here’s the ‘production’ versions of the same code without their illustrative qualities:


 
public bool IsBetweenIncl(IComparable x, IComparable y, IComparable z)
{
  return  ( (x.CompareTo(y) >= 0) != (x.CompareTo(z) >= 0));
}
 
public bool IsBetweenExcl(IComparable x, IComparable y, IComparable z)
{
    return ((x.CompareTo(y) > 0) != (x.CompareTo(z) > 0));
}

Busy writing a compiler

September 24, 2006 on 9:28 pm | In .NET Coding | No Comments

Sorry I haven’t been very postative lately but I’m thoroughly engrossed in writing a compiler at the moment. It’s a virtual machine (virtual virtual machine cause it’s in .net, the irony) and I just need it to compile code to read and write things for me from a non-relational database without getting lots of IF THEN ELSE blah blah logic all over the place, and also allow for some fluidity. So I’m a bit out of the loop, but when I’m done I’m making a point to be the first guy on the web to show a complete example of writing a compiler in c# (more than just that damned calculator example that everyone seems to copy from eachother!)

Later! (for now)

Take This… ObjectDataSource!

September 19, 2006 on 2:30 pm | In .NET Coding | No Comments

Now with Vitamin C!

THIS IS COMPLETELY REVISED, so it bears almost no resemblence, except for the only slightly less than clever title of the article, to it’s former bug-ridden self. All of this code is now included in RegGen 0.4.6 available (again) at http://sourceforge.net/projects/refgen.

First thing’s first, you need an interface to denote cachable objects, and to uniquely identify things, they need, of course an ID. So lets force you to call it ID. Also, for sorting of any kind to work, you also need it to be comparable to itself, so we thus have:


/// <summary>
/// For things that have ID properties.
/// </summary>
public interface IIdentifiable<T>
    where T: IComparable<T>
{
    T ID { get; set; }
}

Next we need to break the access code into two categories: Raw, and possibly cahce buffered.

The Raw Data Source (fancy because of the capital letters) needs to be able to do some basic functions, which if you’re using ADO, are basically automatic. If you’re using a webservice, well you should know how to write that sort of code anyway, or you have no business using webservices as your data source! (haha, just kidding, here’s a link to msdn article on it)


public interface IDataStore<T,K>
        where T: IComparable<T>
        where K: IIdentifiable<T>
    {
        
        List<K> GetAll();
        List<K> GetList(T[] Keys);
        List<K> GetLimitedRange(T StartKey, int MaxRange);
        List<K> GetRange(T StartKey, T EndKey);
        K Get(T id);
        bool Update(K Obj);
        K Insert(K Obj);
        void Delete(T ID);
        
    }

Then, we need something that’s standardized to use the cache. I like to make this easy to remember by making the names slightly longer. You may have a better idea for the names of the methods, and if you do, that’s fine, but this works for me:


public interface IModel<T, K>
        where T : IComparable<T>
        where K : IIdentifiable<T>
    {
        List<K> GetThemAll(bool fromDataStore);
        List<K> GetThese(T[] Objs);
        List<K> GetThese(K[] Objs);
        List<K> GetBetween(T MinID, T MaxID);
        List<K> GetPage(T StartID, int Max);
        K GetOne(K Obj);
        K GetOne(T ID);
        void UpdateOne(K Obj);
        K AddOne(K Obj);
        void DeleteOne(K Obj);
        void DeleteOne(T ID);
 
        System.Data.DataTable GetDataTable();
        System.Data.DataTable GetDataTable(T[] IDs);
 
        void RefreshInvalids();
        void Invalidate(T ID);
        void InvalidateAll();
    }

So what are these for exactly? I mean, how do we get from those to a caching datasource? You probably figure that I’m going to show you, so if you did, you’re correct. Here’s a generic class that implements both the IDataStore and the IModel to give us an abstract class from which you can derive your custom business objects.


public abstract class Model<T,K> : IModel<T,K>, IDataStore<T,K>
        where T: IComparable<T>
        where K: IIdentifiable<T>, new()
    {
 
        static Cache<T, K> cachedItems;
        static List<T> InvalidKeys;
        static bool isNew;
 
        static Model()
        {
            cachedItems = new Cache<T,K>();
            InvalidKeys = new List<T>();
            isNew = true;
        }
 
        #region IModel<T,K> Members
 
        
        public List<K> GetThemAll(bool fromDataStore)
        {
            List<K> items;
 
            if (fromDataStore)
            {
                items = GetAll();
                foreach (K item in items)
                {
                    AddToCache(item);
                }
            }
            else
            {
                RefreshInvalids();
                items = new List<K>();
                foreach (K item in cachedItems.GetValues())
                {
                    items.Add(item);
                }
            }
 
            List<K> toReturn = new List<K>();
            foreach (K item in items)
            {
                toReturn.Add(item);
            }
 
            return toReturn;
        }
 
        private void AddToCache(K item)
        {
            cachedItems.Add(item.ID, item);
        }
 
        private bool isValid(T k)
        {
            return (!InvalidKeys.Contains(k) && cachedItems.ContainsKey(k));
        }
 
        private K resolve(T id)
        {
            K obj = Get(id);
            if (obj != null)
            {
                cachedItems.Add(id, obj);
                
                if (InvalidKeys.Contains(id)) InvalidKeys.Remove(id);
            }
 
            return cachedItems[id];
        }
 
        public List<K> GetThese(T[] Objs)
        {
            List<K> toReturn = new List<K>();
 
            foreach (T item in Objs)
            {
                if (isValid(item))
                {
                    toReturn.Add(cachedItems.GetValue(item));
                    continue;
                }
 
                resolve(item);
                toReturn.Add(cachedItems.GetValue(item));
            }
 
            return toReturn;
        }
 
        public List<K> GetThese(K[] Objs)
        {
            List<K> toReturn = new List<K>();
 
            foreach (K item in Objs)
            {
                if (isValid(item.ID))
                {
                    toReturn.Add(cachedItems.GetValue(item.ID));
                    continue;
                }
 
                resolve(item.ID);
                toReturn.Add(cachedItems.GetValue(item.ID));
            }
 
            return toReturn;
        }
 
        public List<K> GetBetween(T MinID, T MaxID)
        {
            List<K> all = GetThemAll(true);
 
            List<K> toReturn = new List<K>();
 
            // wow! this is cool!
            all.FindAll(delegate(K Obj) { return Obj.ID.CompareTo(MaxID) >= 0 != Obj.ID.CompareTo(MaxID) <= 0;}).ForEach(toReturn.Add);
 
            return toReturn;
        }
 
        
        public List<K> GetPage(T StartID, int Max)
        {
            List<K> all = GetThemAll(false);
            
            all.Sort();
 
            int count = 0;
            List<K> toReturn = new List<K>();
            
            // I'm really liking anonymous delegates for this stuff!
            all.FindAll(delegate(K item) { return (item.ID.CompareTo(StartID) >= 0 && ++count < Max); }).ForEach(delegate(K item) { toReturn.Add(item); });
 
            return toReturn;
        }
 
        /// <summary>
        /// Given an object, call GetOne with the ID -- this doesn't update it, just gets it (so the select method can pass an object as a parameter)
        /// </summary>
        /// <param name="Obj"></param>
        /// <returns></returns>
        public K GetOne(K Obj)
        {
            return GetOne(Obj.ID);
        }
 
        /// <summary>
        /// Get an object from the cache, or from the data store, adding it to the cache on the way.
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public K GetOne(T ID)
        {
            RefreshInvalids();
 
            if (!cachedItems.ContainsKey(ID))
            {
                K storedObj = Get(ID);
 
                if (storedObj != null)
                {
 
                    AddToCache(storedObj);
                    return storedObj;
                }
 
                // the id you asked for isn't in the underlying data source
                return default(K);
            }
 
            return cachedItems[ID];
        }
 
        /// <summary>
        /// Update the object in the underlying data store, and update it in the cache
        /// </summary>
        /// <param name="Obj"></param>
        public void UpdateOne(K Obj)
        {
            if (Update(Obj))
                AddToCache(Obj);
        }
 
        /// <summary>
        /// Add a new object to the underlying data store, and add it to the cache
        /// </summary>
        /// <param name="Obj"></param>
        /// <returns></returns>
        public K AddOne(K Obj)
        {
            K newObj = Insert(Obj);
            if (newObj != null)
                AddToCache(newObj);
 
            return newObj;
 
        }
 
        public void DeleteOne(K Obj)
        {
            DeleteOne(Obj.ID);
        }
 
        public void DeleteOne(T ID)
        {
            // remove it from the cache, if present
            if (cachedItems.ContainsKey(ID))
                cachedItems.Remove(ID);
 
            // remove it from invalid keys, if present
            if (InvalidKeys.Contains(ID))
                InvalidKeys.Remove(ID);
 
            // tell the underlying data store to kill it.
            Delete(ID);
        }
 
        public System.Data.DataTable GetDataTable()
        {
            bool fromDataSource = isNew;
            isNew = false;
 
            return ObjectDataTableFactory<T, K>.GetFilledTable(GetThemAll(fromDataSource));
        }
 
        public System.Data.DataTable GetDataTable(T[] IDs)
        {
            List<K> items = GetThese(IDs);
 
            return ObjectDataTableFactory<T, K>.GetFilledTable(items);
        }
 
        public void RefreshInvalids()
        {
            foreach (T invalidKey in InvalidKeys)
            {
                
                K refreshed = Get(invalidKey);
 
                if (refreshed != null)
                {
                    cachedItems[invalidKey] = refreshed;
                    InvalidKeys.Remove(invalidKey);
                    continue; // skip up and out to the next guy
                }
 
                cachedItems.Remove(invalidKey);
            }
        }
 
        public void Invalidate(T ID)
        {
            InvalidKeys.Add(ID);
        }
 
        public void InvalidateAll()
        {
            foreach (T key in cachedItems.GetKeys())
            {
                if ( ! InvalidKeys.Contains(key) )
                    InvalidKeys.Add(key);
            }
        }
 
        #endregion
 
        /// <summary>
        /// These routines (IDATASTORE) are the ones that you actually implement in your business object,
        /// These are meant to connect to your webservice, SQL database, or whatever you're using for data.
        /// But if you want to access the data buffered through the cache, call the ones from IModel.
        /// </summary>
        /// <returns></returns>
        #region IDataStore<T,K> Members
 
        public abstract List<K> GetAll();
 
        public abstract List<K> GetList(T[] Keys);
 
        public abstract List<K> GetLimitedRange(T StartKey, int MaxRange);
 
        public abstract List<K> GetRange(T StartKey, T EndKey);
 
        public abstract K Get(T id);
 
        public abstract bool Update(K Obj);
 
        public abstract K Insert(K Obj);
 
        public abstract void Delete(T ID);
 
        #endregion
 
    }

As you can see I leave the implementation of the IDataStore to you, but the IModel is pretty much going to work no matter what your backend storage is like.

As I’ve said before, this will allow for you to actually retreive VALUES in the update event args and the insert event args of your update procs for the object datasource. In a normal, non-static backing class for the ODS, you get fresh baked objects (and thus EMPTY values) which basically renders it completely useless. You’ll want to bind your data source for a Master grid view to an object datasource who’s select method is the GetDataTable method, and your Details object data source (that does the actual inserting, updating, and deleting methods for your DetailsView or FormView to the GetOne, InsertOne, UpdateOne, and DeleteOne methods. Don’t worry about parameters, since there are signatures that accept the (K Obj) for each, the ODS will kindly pick the right one for you. One more thing to mention, set EnableCaching to False.

A quick note: the Model tries to fill all of the records the first time you hit it. Note the use of the ‘isNew’ flag. I wasn’t quite sure how most people would like to handle that, so I just defaulted it to that behavior. If you don’t like that (and I can see a bunch of scenarios where you wouldn’t) you can change that, but most likely if you’re randomly frustrated with anything about this code, that’ll be what it is. Also take note that the Cache object has the ability to set a MaxItems number, I default it to 1000 here, but you can change that too. I wanted to give you something usable as is, but I like to point out the parts where people would generally like to make changes, so you don’t just see that it’s not working exactly how you’d like and give up on it. This will save you lots of time. (It does for me.)

I hope you like it, and again, it works now. Cheers!

ObjectDataSource for non-static data = POOP

September 19, 2006 on 10:45 am | In .NET Coding | No Comments

Ok, I’ve heard people rambling off and on about how they don’t like the ObjectDataSource for this and that, but now I’m really seeing what they mean… If you don’t use a static object for the objectdatasoure’s backing source (DataTypeName) then you’re going to get an EMPTY object, freshly baked every single postback! What good is this thing? Guess they assume you will always use a static wrapper. In my case, in which the data comes from a webservice, it’s not nice for me to have to build my own static cache, do my own record locking, and maintain my own concurrency all within the asp.net process. GET REAL FOLKS! MICROSOFT FIX THIS PLEASE!

Also I’d like to know why it doesn’t cache reflection data on the target type. The obvious kneejerk answer to that might be that it’s supposed to allow you to change that type, but, I’m sure they’ve heard of hooking up change events to properties before. It’s not like it would slow things down at all… it’s already calling reflection to iterate the entire type (and it uses BuildManager.FindType() to grab the type by name from the loaded assemblies, and not only that it invokes it with Activator.CreateInstance()) Three slows don’t make a right folks. And the instantiation at each call, I STILL CAN’T BELIEVE IT! HOW STUPID IS THAT!

For a reasonable replacement, check out http://www.manuelabadia.com/products/products.aspx ($$) or a work in progress on a freer one, check out the enlightening illustration on Marc’s blog

EDIT: someone pointed out to me that I link to these guys a lot, and I should stop it.

I know it seems like I’ve been linking to Marc and Manuel a lot, but that’s because they’ve both been up to things that are very similar to the things I’m doing. It’s not that I’m obsessed or stalking them, they’ve just got good stuff to go with the issues concerning me right now. I’m sure that if you wrote something that was pertinent to my topics of discussion, and of course, were I to stumble across it, you’d be a good candidate for links as well. I’m not picky, but I can only credit those whom I know, and who have shown to be knowledgeable by example. So, in short, no I shouldn’t stop it.

Self Doubt…

September 19, 2006 on 1:01 am | In Uncategorized | No Comments

… is what you feel when you’re slowly digging a ditch to run a pipeline from the well, as you watch everyone else go by all day carrying buckets two at a time.

An Open Letter to Terence Parr

September 18, 2006 on 8:53 am | In General Programming | No Comments

Mr Parr,
You never met me, but I’m very well acquainted with you and your work. You’ve produced a set of good tools, and I’ll have to admit that I’ve been inspired by your endeavors. If it weren’t for you and ANTLR, I’d not know what a parser is. I’d never have spent all the time frustrating myself trying to figure out how to write a compiler, or even an interpreter. Overall I can’t blame you for firing my imagination enough to make me want to pursue the now very real possibility of implementing my own language based solutions, but I do blame you for one thing: your famous quote of quotes:

“Why spend 5 days writing by hand what you can spend 5 years of your life automating?”

Yeah that’s right. It’s all your fault. I was so profoundly wounded by that sentiment that it drove me up the wall. It carried over into everything I’ve been working on. I’ve somehow had it in my head that I should never write a line of code by hand again, other than to generate other code, or even code to generate code generators. While this has the potential to be wildly productive… oh say… five years from now, it’s making me look silly to everyone else who’s ripping out RADD apps left and right in front of me! I refuse to wire up a UserControl manually because I just KNOW that I can write a tool to generate it for me, and I absolutely abhor the concept of designing a web page layout IN THE ACTUAL PAGE because surely there is a way for me to abstract it to meta data that will allow me to rattle off three lines of script that will generate a page that will handle any and every single type of input that will ever be devised by man and his future ilk.

I guess the part that I’ve been missing, and, really I have no excuse for it, you’ve provided all the wisdom that I should have needed right there after the ‘when you can spend’, is that part about the ‘five years of your life.’ I mean, I’ve read it enough, and said it enough, and it’s right there in ones and zeros. I should have figured out what that meant by now. But no. Sadly, I’m still on the quest to automate everything, and Terence, it’s all your fault! You corruptor of simple minds!

Sincerely,
Dave

Phew! Finally. I got that out of my system.

Breaking the Rules of C#

September 14, 2006 on 12:58 pm | In .NET Coding | No Comments

Dynamic Casting at Runtime
Now you might think that c# is a strongly typed language, but I’ve just discovered a way that you can squeeze yourself through the door of reasonable doubt, if you happen to be in court trying to prove to the contrary.

Now, no fair emitting IL to emulate VB’s cast, and no fair using Type Conversion (which is more costly in the cases when you actually want to do this). The Dynamic Casting helps if you’re working around the fact that Delegates are NOT covariant with respect to Parameters. (They are with return values).
So, in this case, we just want to spoof the ’signature’ of the delegate out by accepting object, when we actually want to cast it to what it really is in the underlying value. It’s still a typesafe operation, it just kinda pulls the wool over the compiler’s eyes.

Lets say we have a delegate


public delegate object InvokeOp(object value);
 

Let’s also say that we’re screwed and have to call a method that only accepts stronly typed values.


public static FooClass
{
      public static string Op(string value);
 
      public static int Op(int value);
 
      public static DateTime Op(DateTime value);
  
}
 

We’ll say that we want to write a single function that will call the appropriate one of these things at runtime, but we don’t want all this if logic all over the place.


public static class MyInvokerClass
{
      static Dictionary<Type, InvokeOp> Invokers = new Dictionary<Type,InvokeOp>();
 
      static MyInvokerClass()
      {
         //The trick way
         Invokers.Add(typeof(string), delegate(object value) { FooClass.Op((string)value); });
         Invokers.Add(typeof(int), delegate(object value) { FooClass.Op((int)value); });
         Invokers.Add(typeof(DateTime), delegate(object value) { FooClass.Op((DateTime)value); });
      }
 
      // matches the signature of the delegate
      public static object InvokeMethodFor(object value)
      {
           return Invokers[value.GetType()](value);
       }
}
 

There! That wasn’t so bad was it?

That works well for calling methods that need specific types, and anonymous methods seem to let us break the rule (though actually just work around it) of contravariance -> we’re simulating Covariance.

Now that works just fine if you know all the types you want to use at runtime. But, you might say, is there a way that we can get this thing to work generically for all types on any method set like this?

Yes, there is, but I don’t have time to go into it right now. I’ll post back soon.

How to use the Introspector (details)

September 8, 2006 on 4:59 pm | In .NET Coding | No Comments

RefGen is very useful. The UI generation is neat, but the best part is the Introspector. Take anywhere you’d use reflection to enumerate properties and access them dynamically and replace that Type.GetProperty().GetValue() with Introspector.GetProperty(srcObject, “propertyName”). Even better, use it to set properties. Even enumerating properties and their types is a breeze, and you only incur the cost of the reflection once.

First, lets get one thing straight: The function and usage of the Introspector’s methods will not change as I upgrade it, even though the backend will be optimized many times, so it’s safe to give you docs now.

Feature overview of the Introspector:

  • Automated ‘Learning’ of a Type’s properties
  • Dynamic access to properties by name (get, and set)
  • Fast object instantiation by Type name (beat the pants off of Activator.CreateInstance())
  • On-demand enumeration of the properties of a type, as well as access to the Type of each property
  • It’s Free and yes, you can put it in your commercial applications (in compliance with the Apache License v 2.0)

‘Type Learning’ is just a kitty cat way of saying that it enumerates the properties once using refleciton and caches what it finds. The major cost of using normal reflection based classes is incurred during the enumeration. Your average implementation of something using Reflection will run on average about 20 times slower than RefGen* because it will be enumerating or searching the properties with each access. When you make a call to the Introspector, and pass in an object of any type, the first thing it does is check the cache to see if it has been ‘learned.’ If it hasn’t, it learns it right then before proceeding with doing whatever you ask it to do. There is no need to give special instruction to the Introspector to learn the type. (Although you can force it with a blank call to Introspector.PropertyDictionary() without actually getting or setting anything.) The cache is static, so as long as the assembly doesn’t go out of scope, then it’s not going to have to re-learn the type again.

Getting Property Values:


public static object GetProperty(object Obj, string propertyName);
  

Ok, so how do we do it now? I figure I beat up on the Person object all the time, and it’s used to it, so lets use the Person object example from my previous post. Ok, so this is a cheesy, not a practical, example but we’ll talk about practical uses in a bit.


Person me = new Person();
Person.Name = "Dave Dolan";
      
// oh no! I forget what I just typed, so lets read the name again and print it to the console
 
string NameOfMe = (string) Introspector.GetProperty(me, "Name");
 
Console.Out.WriteLine("The value of the Name property for the Person \"me\" is {0}", NameOfMe);
 
  

Setting Property Values:


public static void SetProperty(object Obj, string propertyName, object value);
  

So now we want to set properties. This is just as easy as getting them.


Person me = new Person();
 
Introspector.SetProperty(me, "Name", "Dave Dolan");
      
// oh no! I forget what I just typed, so lets read the name again and print it to the console
 
string NameOfMe = me.Name;
 
Console.Out.WriteLine("The value of the Name property for the Person \"me\" is {0}", NameOfMe);
  

That’s mostly all there is to it with the property access. There is one thing left if you’re very nitpicky about casting too often.

You can save yourself one cast operation in the GetProperty method if you know upfront exactly which type you’re expecting by using the generic form of GetProperty.


public static T GetProperty<T>(object Obj, string propertyName);
  

Internally the output will still be converted to the type specified in the generic, but on the way out, at least you don’t have to cast it in your code. (This is why I say it only saves one cast op)


string NameOfMe = Introspector.GetProperty<string>(me, "Name");
  

Same deal applies with SetProperty, except it saves more like 1.5 casting operations becase when we pass the object typed parameter to the delegate that actually calls the setter, it’ll use implicit type conversion, which is a bit less expensive than a full out cast. (I made the .5 up so it’s 1.something, just for the record.)


Introspector.SetProperty<string>(me, "Name", "Dave Dolan");
  

Now value types (ints, floats, doubles, DateTimes and the like) will still be boxed because they’re passed to the delegate that invokes the setter as the type Object, which is something I hope to change in coming versions. (I’m going to multiplex the cache so that it stores a separate list of delegates for each target type, with strong types implemented directly in the IL.) So for now, figure that boxing still happens.

Property Enumeration:


public static Dictionary<string,Type> PropertyDictionary(object Obj);
 
// OR
 
public static Dictionary<string,Type> PropertyDictionary(Type t);
  

This provides you with a dictionary keyed by string property names, and housing their types. If you’d like the know what type
the “DateOfBirth” property of Person is then you can do this one of two ways, depending on what you know up front.


// using an instance of the object, if you don't know the type at design time
Type DoBType = Introspector.PropertyDictionary(me)["DateOfBirth"];
 
// OR
 
// using a the type of the object, if you happen to know it at design time
Type DoBType = Instrospector.PropertyDictionary(typeof(Person))["DateOfBirth"];
 
  

Up to now all of these methods caused the learning of a type. If you want to create an instance of the object, without being slow like the System.Reflection.Activator() then you can call Introspector.CreateObject(). The only catch is that the type has to have been learned, or you have to specify the assembly qualified name of it (which can be long)


public static object CreateObject(string ShortNameOfTheType);
  

This is particularly good for factories or custom-built data source controls in which you won’t know the type at design time, but
you’ll have already accessed the type using the Introspector before. ( If you haven’t, and you have an instance of it laying around you can call Introspector.PropertyDictionary(instanceOfTheType) and it will do nothing except learn the type) I’ll probably want to have a ’search for the type name’ feature added, but then I’d have to require you specify the full type name instead of just the short type name, or things might get hairy… It’s one of those features where I’d like to get input from people who’d actually use it before I make a decision.


Person meAgain = Introspector.CreateObject("Person") as Person; // note the 'as' clause because it's of type object
  

I hope that you’ll find this library useful, because I know I personally have come up with so many uses for it, like a simple way to generate ORMappers via factories, a way to create ‘linear’ serializers that have zero conditional logic or looping, and a way to ‘debug’ print out any type of object in the universe to the console without caring what kind of object it actually is, and oh, Generating a set of widgets to edit an object via a webpage with the ability to hook up datasources to them (Dolan.RefGen.UI.Web.ObjectWidget). I’m sure there are a million more but I’m just starting on this whole thing. I’d like to be able to do something nice for people without Full Trust too, so I have the idea that maybe I can pregenerate the assembly full of classes instead of delegates on the developers host and allow for it to dynamically load that at runtime. I mean, it’s probably not that often that you’d be using someone else’s classes that you have absolutely no knowledge of (unless you are also dynamically loading assemblies), so it’d work for your ORMapper and similar things still. (Not to mention that it would save on the time it takes to refactor your mappings when requirements change for your project.) Let me know what you think folks, and again the link is http://sourceforge.net/projects/refgen .

I’m so very open to suggestions it’s not even funny.

Lonely footnote from above:
*This is assuming that you are able to use the DynamicMethod in your environment (which requires Full Trust permissions)

One (probably) last thing about dynamic method (for now)

September 6, 2006 on 9:39 pm | In .NET Coding | No Comments

Ok, I admit it. It was all there in blue and white on microsoft’s site the whole time, and I just didn’t read it.

DynamicMethod, how to do it with generics, and yes… also… how to invoke generic type parameters at runtime and even how to return value types….wait for it…. without boxing.

http://msdn2.microsoft.com/en-us/library/exczf7b9.aspx

I hate that I just didn’t see it. Again, thanks to the world of faster catcher onners that helped me out! (Manuel and Marc especially.)

Next Page »

Powered by WordPress with Pool theme design by Borja Fernandez.
Entries and comments feeds. Valid XHTML and CSS. ^Top^