Having fun with Reflection
- by Nick Harrison
I was once asked in a technical interview what I could tell them about Reflection. My response, while a little tongue in cheek was that "I can tell you it is one of my favorite topics to talk about"
I did get a laugh out of that and it was a great ice breaker. Reflection may not be the answer for everything, but it often can be, or maybe even should be.
I have posted in the past about my favorite CopyTo method. It can come in several forms and is often very useful. I explain it further and expand on the basic idea here
The basic idea is to allow reflection to loop through the properties of two objects and synchronize the ones that are in common. I love this approach for data binding and passing data across the layers in an application.
Recently I have been working on a project leveraging Data Transfer Objects to pass data through WCF calls. We won't go into how the architecture got this way, but in essence there is a partial duplicate inheritance hierarchy where there is a related Domain Object for each Data Transfer Object. The matching objects do not share a common ancestor or common interface but they will have the same properties in common. By passing the problems with this approach, let's talk about how Reflection and our friendly CopyTo could make the most of this bad situation without having to change too much.
One of the problems is keeping the two sets of objects in synch. For this particular project, the DO has all of the functionality and the DTO is used to simply transfer data back and forth. Both sets of object have parallel hierarchies with the same properties being defined at the corresponding levels. So we end with BaseDO, BaseDTO, GenericDO, GenericDTO, ProcessAreaDO, ProcessAreaDTO, SpecializedProcessAreaDO, SpecializedProcessAreaDTO, TableDo, TableDto. and so on.
Without using Reflection and a CopyTo function, tremendous care and effort must be made to keep the corresponding objects in synch. New properties can be added at any level in the inheritance and must be kept in synch at all subsequent layers. For this project we have come up with a clever approach of calling a base GetDo or UpdateDto making sure that the same method at each level of inheritance is called. Each level is responsible for updating the properties at that level.
This is a lot of work and not keeping it in synch can create all manner of problems some of which are very difficult to track down. The other problem is the type of code that this methods tend to wind up with.
You end up with code like this:
Transferable dto = new Transferable();
base.GetDto(dto);
dto.OfficeCode = GetDtoNullSafe(officeCode);
dto.AccessIndicator = GetDtoNullSafe(accessIndicator);
dto.CaseStatus = GetDtoNullSafe(caseStatus);
dto.CaseStatusReason = GetDtoNullSafe(caseStatusReason);
dto.LevelOfService = GetDtoNullSafe(levelOfService);
dto.ReferralComments = referralComments;
dto.Designation = GetDtoNullSafe(designation);
dto.IsGoodCauseClaimed = GetDtoNullSafe(isGoodCauseClaimed);
dto.GoodCauseClaimDate = goodCauseClaimDate;
One obvious problem is that this is tedious code. It is error prone code. Adding helper functions like GetDtoNullSafe help out immensely, but there is still an easier way.
We can bypass the tedious code, by pass the complex inheritance tricks, and reduce all of this to a single method in the base class.
TransferObject dto = new TransferObject();
CopyTo (this, dto);
return dto;
In the case of this one project, such a change eliminated the need for 20% of the total code base and a whole class of unit test cases that made sure that all of the properties were in synch.
The impact of such a change also needs to include the on going time savings and the improvements in quality that can arise from them. Developers who are not worried about keeping the properties in synch across mirrored object hierarchies are freed to worry about more important things like implementing business requirements.