Problem loading rules from database on generic methods

Problem loading rules from database on generic methods

Old forum URL: forums.lhotka.net/forums/t/4194.aspx


david.wendelken posted on Friday, January 18, 2008

I've been moving the assignment of business rules from hard-coded statements in AddBusinessRules() to a generic routine that loads them from a database.

It's working great except when the rule method is a generic.  Then it barfs.

Here's the relevant code:

-- loop thru custom classes holding the data needed to create the rule.
foreach
(PropertyRuleInfo rule in ruleInstructionInfo.Rules) 
{
   -- @TODO: optimize this so we don't have to load the assembly each time.
   System.Reflection.
Assembly ruleAssembly
           = System.Reflection.
Assembly
.Load(rule.RuleAssemblyName);

   Type t = ruleAssembly.GetType(rule.RuleObjectName);

   System.Reflection.MethodInfo mi = t.GetMethod(rule.RuleMethodName);

   RuleHandler rh;

   try
   {
     
rh = (
RuleHandler)System.Delegate.CreateDelegate
                                      (
typeof(RuleHandler), mi);

The above code works great for StringMaxLength but gives an error on MaxValue<T>. 

ruleAssembly, t and mi all have correct values.  But I can't get it to assign a value to rh for MaxValue<T>.  Seems like it can't find it somehow.

Ideas?

 

tmg4340 replied on Friday, January 18, 2008

I'm a little hazy on this, and it probably would help if you posted the exact error, but I think your problem is that the delegate for generic methods is not RuleHandler - it's RuleHandler<T, R>.  The "R" part of the generic is filled in for you if you don't supply it.  Given that, it probably can't create the delegate because it can't cast the delegate appropriately.

- Scott

david.wendelken replied on Friday, January 18, 2008

I hit a different problem and can't get back to that code point to get the exact error message yet. :(

The different RuleHandler is a great hint.  Thanks!

Short of a case statement that checks for each expected T value (NOT a plan that I like!!), I haven't a clue of how to code it.

How would I write C# code to "fill in the blanks" with the correct T value?

T is normally "hard-coded".  How can I fill in the value from a database string and make it work?

david.wendelken replied on Friday, January 18, 2008

Here's the error message:

[System.ArgumentException] {"Error binding to target method."} System.ArgumentException

Stack Trace:

at System.Delegate.BindToMethodInfo(Object target, RuntimeMethodHandle method, RuntimeTypeHandle methodType, DelegateBindingFlags flags)

at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)

at System.Delegate.CreateDelegate(Type type, MethodInfo method)

at <someplace in my custom class>


david.wendelken replied on Friday, January 18, 2008

david.wendelken:

Short of a case statement that checks for each expected T value (NOT a plan that I like!!), I haven't a clue of how to code it.

How would I write C# code to "fill in the blanks" with the correct T value?

T is normally "hard-coded".  How can I fill in the value from a database string and make it work?

Ok, I think I know how to go about it.  I think I need to do a type(myClassNameVariable).  :) But that could be just wishful thinking. :(

tmg4340 replied on Friday, January 18, 2008

Well - I hate to be the bearer of bad tidings, but you may not be able to.  I am by no means a reflection expert, especially when it comes to generic types.  But some digging into MSDN seems to indicate that methods containing "open generic constructs" - of which this may be - cannot be invoked via reflection.  To definitively find that out, check the "ContainsGenericParameters" property of your MethodInfo object - if it is "true", then I think you're out of luck.

Like I said, I am not a reflection expert.  Furthermore, any documentation I might have about even doing this is not here in the office.  So I wouldn't let this kill your hopes.

simon_may replied on Friday, January 18, 2008

You need to create a closed generic method. the quickest was to describe is to give you a snippet form something I did today

-----

Type[] compParam = new Type[] { typeof(string) };

_comparitorType = Type.GetType("CriteriaComparitor").MakeGenericType(typeof (string));

_compMethod = _comparitorType.GetMethod("Equal", compParam).MakeGenericMethod(typeof(string));

----

It is the use of the MakeGenericXXXX methods on types and methodinfos that does the trick. Coverts them from open genrics to closed generics You can use the GetGenericArguments and similar methods if you want to interogate Types and Methods, Loads of info in Help and MSDN

I hope that helps

Simon

vdhant replied on Tuesday, January 22, 2008

I know that this might not be exactly what you are after but i have done this in the past:

int value = 10;
Type type = value.GetType();
Type listGeneric = typeof(List<>);
Type listConcrete = listGeneric.MakeGenericType(new Type[]{type});
object o = Activator.CreateInstance(listConcreate);

david.wendelken replied on Thursday, January 24, 2008

Simon,

Thanks for giving me a hint!

 

Copyright (c) Marimer LLC