Truely Dynamic Classes?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

(Sorry but I'll be using C# for examples, skip to the last paragraph if you
just want to read my main query)
Ever since Turbo Pascal 5 I've used data created at compile time to
'outline' a database structure that can then be used by functions in a
generic manner. For example, the compiled data would contain column names,
datatypes and special flags. Using a generic function, i.e. GetFieldValue,
you would pass it a pointer to the column definition & it would do all the
data retrieval, type & validation checking based on what was in the
definition. At first this was mainly an intellectual exercise, but thanks to
object orientated programing it has become a huge timesaver for large
projects. Using .NET has made it even better. (the base classes take the most
time, but for every 'chunk' of data after that it's a snap, just derive &
define)

This is a sort-of C# outline to show what I mean. The actual implementation
uses a base class (containing the definition structures, a virtual property
that exposes the definition data, & the generic functions), and derived
classes (containing static variables holding the definition data, the
property override that exposes the definition data, & specific functions that
call the generic functions)

struct ColumnDef {
string columnName;
Type dataType;
}
struct TableDef {
string tableName;
ColumnDef[] columns;
}
struct DatabaseDef {
string dbName;
TableDef[] tables;
}
public DatabaseDef OutlineVariable = {'Sample Database',
{'TableA', {'id', Guid}, {'title', String}},
{'TableB', {'id', Guid}, {'author', String}},
{'TableC', {'titleid', Guid}, {'authorid', Guid}}};
public object Generic_GetFieldValue(ColumnDef column) {
<.. The logic here varies (language,platform,etc) but what we want to do
is:
connect to the column.parent(tabledef).parent(databasedef) database
get the column.parent(tabledef) table data
lookup the column.columnName column
type check against column.dataType (errors go elsewhere)
return an object that the programer KNOWS is of the right type to work
with the column (& sometimes, KNOWS is not a null)
..>
}

Now some of you might be thinking, "Hang on! That's a Typed Dataset!", and
you would be partly right, but that's not the direction my query is going.
Although a Typed Dataset would replace this code, it cannot create the
adapters necessary to get/set the database data. While using this code you
can use a generic function to create the adapters you need (sorta like
commandbuilder).

So, while I still use this code for creating data-adapter/table/set(s) I no
longer use it for actual data manipulation. However there is still a lot of
code syncronisation needed to make sure the derived classes match the
database definitions. You still have to hard-code the shortcut properties,
i.e. Database.TableA.idColumn, otherwise you're still typing twice as much
and not saving much time.

This leads me (finally) to my question. Is it possible to dynamically
construct (or modify) a class (in code), so that some/all of the
members/methods appear/disappear based on static compile-time definition
data? For example, I have a database class, where the definition data
includes a table ('TableA') with two columns ('ID' & 'Title'). When the class
is created (either using new, or a return result from a function that does
the modifying) The TableA property/method is created that allows me access to
the column definitions & actual data.

Feel free to contact me if you want to see some of the code I've actually
got going, or such. (remove the .nospam) (e-mail address removed)
 
(abridged)
This leads me (finally) to my question. Is it possible to dynamically
construct (or modify) a class (in code), so that some/all of the
members/methods appear/disappear based on static compile-time definition
data? For example, I have a database class, where the definition data
includes a table ('TableA') with two columns ('ID' & 'Title'). When the
class
is created (either using new, or a return result from a function that does
the modifying) The TableA property/method is created that allows me access
to
the column definitions & actual data.

You can create new classes dynamically by using the classes in the
System.Reflection.Emit namespace. Existing classes cannot be altered
directly, but you can wrap them with a proxy at runtime to decorate a class
with additional methods, properties and fields. You can even replace method
implementations using a proxy. The .NET framework lets you proxy any class
that extends the ContextBound class with the
System.Runtime.Remoting.Proxies.RealProxy.
If you want a non-intrusive proxy you'll have to use refelction emit to
create a dynamic proxy. Instead of rolling your own dyanmic proxy, I suggest
that you have a look at the Castle Project's dynamic proxy
http://www.castleproject.org/dynamicproxy/.
This implementation is also used by many O/R mapping technologies such as
NHibernate, Retina.NET and iBatis.NET. These frameworks have similar
functionality to what you described, so it might be a good idea to
investegate these further as well.
http://nhibernate.sourceforge.net/
http://www.sf.net/projects/ibatisnet
http://www.sf.net/projects/ibatisnet

Anders Norås
http://dotnetjunkies.com/weblog/anoras/
 
Back
Top