The concepts encapsulated by the
IObjectWrapper
interface are fundamental to the
workings of the core Spring.NET libraries The typical application
developer most probably will not ever have the need to use the
IObjectWrapper
directly... because this is
reference documentation however, we felt that some explanation of this
core interface might be right. The IObjectWrapper
is explained in this chapter since if you were going to use it at all, you
would probably do that when trying to bind data to objects, which, nicely
enough, is precisely the area that the
IObjectWrapper
addresses.
One quite important concept of the Spring.Objects
namespace is encapsulated in the definition
IObjectWrapper
interface and its corresponding
implementation, the ObjectWrapper
class. The
functionality offered by the IObjectWrapper
includes methods to set and get property values (either individually or in
bulk), get property descriptors (instances of the
System.Reflection.PropertyInfo
class), and to query
the readability and writability of properties. The
IObjectWrapper
also offers support for nested
properties, enabling the setting of properties on subproperties to an
unlimited depth. The IObjectWrapper
usually isn't
used by application code directly, but by framework classes such as the
various IObjectFactory
implementations.
The way the IObjectWrapper
works is partly
indicated by its name: it wraps an object to perform
actions on a wrapped object instance... such actions would include the
setting and getting of properties exposed on the wrapped object.
Note: the concepts explained in this section are not
important to you if you're not planning to work with the
IObjectWrapper
directly.
Setting and getting properties is done using the
SetPropertyValue()
and
GetPropertyValue()
methods, for which there are
a couple of overloaded variants. The details of the various overloads
(including return values and method parameters) are all described in the
extensive API documentation supplied as a part of the Spring.NET
distribution.
The aforementioned SetPropertyValue()
and
GetPropertyValue()
methods have a number of
conventions for indicating the path of a property. A property path is an
expression that implementations of the
IObjectWrapper
interface can use to look up the
properties of the wrapped object; some examples of property paths
include...
Path | Explanation |
---|---|
name | Indicates the name property of the
wrapped object. |
account.name | Indicates the nested property name
of the account property of the wrapped
object. |
account[2] | Indicates the third element of the
account property of the wrapped object.
Indexed properties are typically collections such as
lists and dictionaries ,
but can be any class that exposes an indexer. |
Below you'll find some examples of working with the
IObjectWrapper
to get and set properties.
Consider the following two classes:
[C#] public class Company { private string name; private Employee managingDirector; public string Name { get { return this.name; } set { this.name = value; } } public Employee ManagingDirector { get { return this.managingDirector; } set { this.managingDirector = value; } } }
[C#] public class Employee { private string name; private float salary; public string Name { get { return this.name; } set { this.name = value; } } public float Salary { get { return salary; } set { this.salary = value; } } }
The following code snippets show some examples of how to retrieve
and manipulate some of the properties of
IObjectWrapper
-wrapped Company
and Employee
instances.
[C#] Company c = new Company(); IObjectWrapper owComp = new ObjectWrapper(c); // setting the company name... owComp.SetPropertyValue("name", "Salina Inc."); // can also be done like this... PropertyValue v = new PropertyValue("name", "Salina Inc."); owComp.SetPropertyValue(v); // ok, let's create the director and bind it to the company... Employee don = new Employee(); IObjectWrapper owDon = new ObjectWrapper(don); owDon.SetPropertyValue("name", "Don Fabrizio"); owComp.SetPropertyValue("managingDirector", don); // retrieving the salary of the ManagingDirector through the company float salary = (float)owComp.GetPropertyValue("managingDirector.salary");
Note that since the various Spring.NET libraries are compliant
with the Common Language Specification (CLS), the resolution of
arbitrary strings to properties, events, classes and such is performed
in a case-insensitive fashion. The previous examples were all written in
the C# language, which is a case-sensitive language, and yet the
Name
property of the Employee
class was set using the all-lowercase 'name'
string
identifier. The following example (using the classes defined previously)
should serve to illustrate this...
[C#] // ok, let's create the director and bind it to the company... Employee don = new Employee(); IObjectWrapper owDon = new ObjectWrapper(don); owDon.SetPropertyValue("naMe", "Don Fabrizio"); owDon.GetPropertyValue("nAmE"); // gets "Don Fabrizio" IObjectWrapper owComp = new ObjectWrapper(new Company()); owComp.SetPropertyValue("ManaGINGdirecToR", don); owComp.SetPropertyValue("mANaGiNgdirector.salARY", 80000); Console.WriteLine(don.Salary); // puts 80000
The case-insensitivity of the various Spring.NET libraries (dictated by the CLS) is not usually an issue... if you happen to have a class that has a number of properties, events, or methods that differ only by their case, then you might want to consider refactoring your code, since this is generally regarded as poor programming practice.
In addition to the features described in the preceding sections there a number of features that might be interesting to you, though not worth an entire section.
determining readability and
writability: using the IsReadable()
and IsWritable()
methods, you can determine
whether or not a property is readable or writable.
retrieving PropertyInfo instances:
using GetPropertyInfo(string)
and
GetPropertyInfos()
you can retrieve instances
of the System.Reflection.PropertyInfo
class, that might come in handy sometimes when you need access to
the property metadata specific to the object being wrapped.
If you associate a TypeConverter
with the
definition of a custom Type
using the standard .NET
mechanism (see the example code below), Spring.NET will use the associated
TypeConverter
to do the conversion.
[C#] [TypeConverter (typeof (FooTypeConverter))] public class Foo { }
The TypeConverter
class from the
System.ComponentModel
namespace of the .NET BCL is used
extensively by the various classes in the Spring.Core
library, as said class “... provides a unified way of converting
types of values to other types, as well as for accessing standard values
and subproperties.” [4]
For example, a date can be represented in a human readable format
(such as 30th August 1984
), while we're still able to
convert the human readable form to the original date format or (even
better) to an instance of the System.DateTime
class. This behavior can be achieved by using the standard .NET idiom of
decorating a class with the TypeConverterAttribute
.
Spring.NET also offers another means of associating a
TypeConverters
with a class. You might want to do
this to achieve a conversion that is not possible using standard idiom...
for example, the Spring.Core
library contains a custom
TypeConverter
that converts comma-delimited strings
to String array instances. Registering custom converters on an
IObjectWrapper
instance gives the wrapper the
knowledge of how to convert properties to the desired
Type
.
An example of where property conversion is used in Spring.NET is the
setting of properties on objects, accomplished using the aforementioned
TypeConverters
. When mentioning
System.String
as the value of a property of some
object (declared in an XML file for instance), Spring.NET will (if the
type of the associated property is System.Type
) use
the RuntimeTypeConverter
class to try to resolve
the property value to a Type
object. The example
below demonstrates this automatic conversion of the
Example.Xml.SAXParser
(a string) into the corresponding
Type
instance for use in this factory-style class.
<objects xmlns="http://www.springframework.net"> <object id="parserFactory" type="Example.XmlParserFactory, ExamplesLibrary" destroy-method="Close"> <property name="ParserClass" value="Example.Xml.SAXParser, ExamplesLibrary"/> </object> </objects>
[C#] public class XmlParserFactory { private Type parserClass; public Type ParserClass { get { return this.parserClass; } set { this.parserClass = value; } } public XmlParser GetParser () { return Activator.CreateInstance (ParserClass); } }
The default type converter for enumerations is the
System.ComponentModel.EnumConverter
class. To
specify the value for an enumerated property, simply use the name of the
property. For example the TestObject
class has a
property of the enumerated type FileMode
. One of
the values for this enumeration is named Create
. The
following XML fragment shows how to configure this property
<object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests"> <property name="name" value="Rod"/> <property name="FileMode" value="Create"/> </object>
Spring.NET has a number of built-in
TypeConverters
to make life easy. Each of those is
listed below and they are all located in the
Spring.Objects.TypeConverters
namespace of the
Spring.Core
library.
TypeConverters
Type | Explanation |
---|---|
RuntimeTypeConverter | Parses strings representing
System.Types to actual
System.Types and the other way
around. |
FileInfoConverter | Capable of resolving strings to a
System.IO.FileInfo object. |
StringArrayConverter | Capable of resolving a comma-delimited list of strings to a string-array and vice versa. |
UriConverter | Capable of resolving a string representation of a URI to
an actual Uri -object. |
FileInfoConverter | Capable of resolving a string representation of a
FileInfo to an actual
FileInfo -object. |
StreamConverter | Capable of resolving Spring IResource URI (string) to its
corresponding InputStream -object. |
ResourceConverter | Capable of resolving Spring IResource URI (string) to an
IResource object. |
ResourceManagerConverter | Capable of resolving a two part string (resource name,
assembly name) to a
System.Resources.ResourceManager
object. |
RgbColorConverter | Capable of resolving a comma separated list of Red,
Green, Blue integer values to a
System.Drawing.Color structure. |
RegexConverter | Converts string representation of regular expression into an instance of System.Text.RegularExpressions.Regex |
Spring.NET uses the standard .NET mechanisms for the resolution of
System.Types
, including, but not limited to
checking any configuration files associated with your application,
checking the Global Assembly Cache (GAC), and assembly probing.
You can register a custom type converter either Programatically using the class TypeConverterRegistry or through configuration of Spring's container and described in the section Registering Type Converters.
[4] More information about creating custom
TypeConverter
implementations can be found online
at Microsoft's MSDN website, by searching for Implementing a
Type Converter.