PDA

View Full Version : AOP + type parameter constraints = TypeLoadException



joshua.ball
06-18-2008, 01:11 PM
At first glance, this post might look like an nhibernate question, but I believe
the error message I am receiving has more to do with AOP
then it does with nhibernate. I am presenting this in the context of nhibernate because people are familiar with it and can easily see the practical benefit of what I am trying to do.

Here is my problem. Instead of making calls like this:


IList<Employee> = myService.GetEmployeesByLocation(locationId);
IList<Location> = myService.GetLocationsByCountry(countryId);
IList<Employee> = myService.GetEmployeesByDepartment(departmentId);

I want to be able to make calls like this:


IList<Employee> = myService<Employee>.GetBy<Location>(locationId);
IList<Location> = myService<Location>.GetBy<Country>(countryId);
IList<Employee> = myService<Employee>.GetBy<Department>(departmentId);

The reason is obvious. In the first case I have to write 3 methods in my service layer. In the second I only have to write one.

Here is my proposed solution:



public class MyService<TObject> {
public IList<TObject> GetBy<TObj, A>(int objectId) where TObj : TObject, IGetBy<A>
{
if (objectId <= 0) return null;
ICriteria criteria = Session.CreateCriteria(typeof(TObject));

string property = typeof(A).Name;

criteria.Add(new EqExpression(property + ".Id", objectId));

return criteria.List<TObject>();
}
}


That type signature may be a little confusing. What I really want to say is this:


public IList<TObject> GetBy<A>(int objectId) where TObject : IGetBy<A>

but that does not compile. =/ Thus the additional TObj type parameter, which I always pass in as the same type as TObject. So my calls actually end up looking like this:


IList<Employee> = myService<Employee>.GetBy<Employee,Location>(locationId);
IList<Location> = myService<Location>.GetBy<Location,Country>(countryId);
IList<Employee> = myService<Employee>.GetBy<Employee,Department>(countryId);

To prevent non-sense queries like the following:


IList<Employee> = myService<Employee>.GetBy<FruitSalad>(fruitSaladId);

I have created an empty interface called IGetBy`1, and implemented it on classes only where it makes sense.


public interface IGetBy<A> { /* empty interface */ }

public class Employee : IGetBy<Location>, IGetBy<Department> {
...
public virtual Location Location { get; set; }
...
public virtual Department Department { get; set; }
...
}

public class Location : IGetBy<Country> {
...
public virtual Country Country { get; set; }
...
}

A unit test verifies for me that all classes in the assembly which implement IGetBy`1 have a property whose name is the same as the type name. If the unit test passes, then I know that only valid EqExpression will be constructed in MyService.GetBy<,>(...).

Everything seemed clean and beautiful, until I started up the project, and I got the following error message:


System.TypeLoadException: Method 'GetBy' on type 'CompositionAopProxy_1f73a05af11343d3838a425296467 d99' from assembly 'Spring.Proxy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' tried to explicitly implement an interface method with weaker type parameter constraints.

I assume it's talking about the following:


public IList<TObject> GetBy<TObj, A>(int objectId) where TObj : TObject, IGetBy<A>

Does Spring not support AOP across calls to methods with type parameter constraints? Or am I doing something wrong? If not, are there any work-arounds?

joshua.ball
06-18-2008, 07:23 PM
I found a work-around.

I changed

public IList<TObject> GetBy<TObj, A>(int objectId) where TObj : TObject, IGetBy<A>

to

public IList<TObj> GetBy<TObj, A>(int objectId) where TObj : IGetBy<A>


Should this be considered a bug in Spring.AOP?

Bruno Baia
06-23-2008, 07:47 AM
Hi,

I don't understand that constraints :


where TObj : TObject

ex : Why 'Location' have to inherit from 'Employee' ?

- Bruno