Invoking method with generic parameters


A

Andrus

I tried code below but it fails since mi is null.
For strange reason GetMethod does not find Add method.
How to invoke method with generic parameters?

Andrus.

public abstract class EntityBase {

void Add<TEntity>(object sender) where TEntity : EntityBase { }

public void CreateAndAdd(object sender) {
var mi = GetType().GetMethod("Add");
var gm = mi.MakeGenericMethod(GetType());
gm.Invoke(this, new object[] { sender });
}

}
 
Ad

Advertisements

A

Andrus

Pete,

I need to call DbLinq GetTable() method in my entity base class:

public abstract class EntityBase {

void Add<TEntity>(object sender) where TEntity : EntityBase
{
using (var db = new Database())
{
var doktemp = db.GetTable<TEntity>();
doktemp.InsertOnSubmit(this);
db.SubmitChanges();
}
}
....

I need to pass calling entity type to dbLinq GetTable<>() method type
parameter.
How to pass type (returned by GetType()) to a GetTable() type parameter ?

Andrus.
 
A

Andrus

Pete,
All that said, it seems to me that one possible approach would be to make
the method static and use type inference:

Thank you.
Following code works OK but requires switch for every entity type:

public abstract class EntityBase {
void Add<TEntity>(object instance, object sender) where TEntity :
EntityBase
{
OnSaving(sender);
using (var db = new Database())
{
var doktemp = db.GetTable<TEntity>();
doktemp.InsertOnSubmit(instance);
db.SubmitChanges();
}
}

public void CreateAndAdd(object sender)
{
switch (GetType().Name)
{

case "CartKaardika":
Add<CartKaardika>(this, sender);
break;

case "Artpilt":
Add<Artpilt>(this, sender);
break;

case "KuulutusKaardika":
Add<KuulutusKaardika>(this, sender);
break;

default:
throw new InvalidOperationException(GetType().Name);
}
}


using your great suggestion I changed this code so that it does not require
switch but uses type inference:

public abstract class EntityBase {
static void Add<TEntity>(TEntity instance, object sender) where
TEntity : EntityBase
{
instance.OnSaving(sender);
using (var db = new Database())
{
var doktemp = db.GetTable<TEntity>();
//System.ApplicationException: InsertClauseBuilder need to
receive types that have ColumnAttributes
// at DbLinq.Linq.Table`1.SaveAll_unsafe(ConflictMode
failureMode) in I:\raamat\Eeva\dblinq\DbLinq\Linq\Table.cs:line 426
doktemp.InsertOnSubmit(instance);
db.SubmitChanges();
}
}

public void CreateAndAdd(object sender)
{
Add(this, sender);
}
}

New code causes exception show in comment in DbLinq ( http://linq.to/db )
InsertOnSubmit method.
How to fix this so that changed code works in same way as original ?
Also I don't understand why Add<> must be static. I tried with instance
Add<> but same exception occurs.

Andrus.
 
A

Andrus

Peter,
Note that even with type inference, it's not going to work unless the
variable used as the argument is statically typed as the desired type. If
you've got (for example) an instance of CartKaardika, but are referring to
it with a variable typed as EntityBase, then you'll get the wrong type. ....
(though again, you'll have to make the CreateAndAdd() method generic also
for this to work, so that you _can_ provide the type parameter...note
that you should only have to provide the actual type once, at the first,
top-level method you're calling, since after that you can just pass the
type parameter down to each subsequence generic method as part of the
method name).

Thank you very much for your time.
My top-level method is asmx web service implementation. I call
CreateAndAdd() from web method which can be used to add any type of entity.
Entity is created using Factory pattern:

[WebMethod()]
public string AddNew(string headerEntity) {
EntityBase entityBase = EntityFactory.Create(headerEntity);
entityBase.CreateAndAdd(this);
return "Entity of type "+entityBase.GetType().Name + " added";
}

There is *nowhere* exact type which can be passed as type parameter to
CreateAndAdd.
How to make CreateAndAdd method generic ?
Is the reflection code which I provided in former post only solution for
this issue?

Andrus.
 
A

Andrus

Peter,

thank you very much.

I call CreateAndAdd() from generic method which can be used to add eny
entity type:

[WebMethod()]
public string AddNew(string headerEntity) {
EntityBase entityBase = EntityFactory.Create(headerEntity);
entityBase.CreateAndAdd(this);
return "Entity of type "+entityBase.GetType().Name + " added";
}

How this sample can be used to solve my issue?

Andrus.
 
Ad

Advertisements

A

Andrus

Pete,
No, it's not necessarily the only solution. However, unless you post a
concise-but-complete code example that reliably demonstrates exactly what
you're doing, I can only continue to make guesses as to what might or
might not work for you.

Thank you.
You quesses seems to be 100% presice for my case.
I think that if you want to only modify code in the EntityBase class
itself, by definition reflection would be your only possible solution,
since you've stated specifically that at no point during the call chain do
you have the actual type in hand (which is necessary for providing a
generic type parameter).

Sadly this seems to be true. My endpoint in web service generic Add method
which receives entity name as parameter.
Earlier you wrote that Add method name is wrong and suggested to find
correct generic method name. I tried code for this:

public abstract class EntityBase
{
void Add<TEntity>(object instance, object sender) where TEntity :
EntityBase
{ ....
}

public void CreateAndAdd(object sender)
{
var meth = GetType().GetMethods(BindingFlags.NonPublic |
BindingFlags.Instance);

var mi = GetType().GetMethod("Add", BindingFlags.NonPublic |
BindingFlags.Instance);
var gm = mi.MakeGenericMethod(GetType());
gm.Invoke(this, new object[] { sender });
....
}

I set breakpoint after meth variable assignment and watched its values in
Watch window.
Suprisingly meth variable does not contain *any Add* method. It contains 11
methods:

- meth {System.Reflection.MethodInfo[11]} System.Reflection.MethodInfo[]
+ [0] {MyApp.Business.QueryBuilder GetSql(MyApp.Business.Kontekst,
Eeva.Business.FormDefinition ByRef,MyApp.Business.FormLayout)}
System.Reflection.MethodInfo {System.Reflection.RuntimeMethodInfo}
+ [1] {Void OnPropertyChanged(System.String)} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [2] {System.String GetFrom(MyApp.Business.FormDefinition,
Eeva.Business.FormLayout)} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [3] {System.String BaseTableAlias()} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [4] {System.Collections.Generic.IList`1[System.String]
GetSelectList(MyApp.Business.FormDefinition)} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [5] {System.String GetExpression(Eeva.Business.FormField)}
System.Reflection.MethodInfo {System.Reflection.RuntimeMethodInfo}
+ [6] {System.Collections.Generic.IList`1[System.String]
DisplayOrder(Int32, System.String)} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [7] {Void AppendWhere(MyApp.Business.QueryBuilder,
Eeva.Business.Kontekst)} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [8] {System.String[] get_RequiredFields()} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [9] {Void Finalize()} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}
+ [10] {System.Object MemberwiseClone()} System.Reflection.MethodInfo
{System.Reflection.RuntimeMethodInfo}


How to fix this code so that Add<TEntity> can be called with real type ?
How to find Add<TEntity> method name for GetMethod ?

Andrus.
 
P

Paul

you need to specify the signature by passing an array of types for the
specific method you are trying to invoke..


Peter Duniho said:
[...]
How to fix this code so that Add<TEntity> can be called with real type ?
How to find Add<TEntity> method name for GetMethod ?

It looks to me like you didn't ask for inherited methods. Look more
closely at the documentation for Type.GetMethods(); you can provide
"binding flags" to get methods other than the ones returned in the default
case.

If that doesn't solve it, you need to post a concise-but-complete code
example that reliably demonstrates the problem (in this case, the attempt
to retrieve the method names).

Pete
 
P

Paul

you need to specify the signature by passing an array of types for the
specific method you are trying to invoke..


Peter Duniho said:
[...]
How to fix this code so that Add<TEntity> can be called with real type ?
How to find Add<TEntity> method name for GetMethod ?

It looks to me like you didn't ask for inherited methods. Look more
closely at the documentation for Type.GetMethods(); you can provide
"binding flags" to get methods other than the ones returned in the default
case.

If that doesn't solve it, you need to post a concise-but-complete code
example that reliably demonstrates the problem (in this case, the attempt
to retrieve the method names).

Pete
 
A

Andrus

It doesn't find it because "Add" isn't the name of the method.

I was able to get this generic Add method using GetType().GetMethod("Add");

So this statement is completely wrong. Add *is* name of the method.

Andrus.
 
A

Andrus

It doesn't find it because "Add" isn't the name of the method.

I was able to get this generic Add method using GetType().GetMethod("Add");

So this statement is completely wrong. Add *is* name of the method.

Andrus.
 
Ad

Advertisements

A

Andrus

Peter,
Thanks for the clarification. I take it you have found the correct
binding flags and now have your code working to your satisfaction?

Correct line is:

var mi = typeof(EntityBase).GetMethod("Add", BindingFlags.NonPublic |
BindingFlags.Instance);

- GetType() *cannot* be used to call private method in derived class !!!
Add() call from code works but Add() call from reflection does not work!

- Binding flags were missing

Andrus.
 
A

Andrus

Peter,
Thanks for the clarification. I take it you have found the correct
binding flags and now have your code working to your satisfaction?

Correct line is:

var mi = typeof(EntityBase).GetMethod("Add", BindingFlags.NonPublic |
BindingFlags.Instance);

- GetType() *cannot* be used to call private method in derived class !!!
Add() call from code works but Add() call from reflection does not work!

- Binding flags were missing

Andrus.
 
P

Paul

Calm down. We are all trying to help people.

Andrus actually came back with this
I was able to get this generic Add method using GetType().GetMethod("Add");

So GetMethod was not too far off course was it. Secondly there was talk
about 11 Add methods possibly which I misread. But my thoughts were still
valid just not in this context so get off your high horse.
 
Ad

Advertisements

P

Paul

Calm down. We are all trying to help people.

Andrus actually came back with this
I was able to get this generic Add method using GetType().GetMethod("Add");

So GetMethod was not too far off course was it. Secondly there was talk
about 11 Add methods possibly which I misread. But my thoughts were still
valid just not in this context so get off your high horse.
 
P

Paul

LOL

Actually it does not bother me at all...

The only mistake I made was posting a reply to your post rather than put the
post elsewhere which is why I said get off your high horse.

Right now I actually find it amusing that some people on here get so touchy.





Peter Duniho said:
Calm down. We are all trying to help people.

Who's not calm?
[...] so get off your high horse.

Oh, right. You're not calm.

I suggest that you calm down.

It's unfortunate that it bothers you to have posted a reply to my post
that was in fact irrelevant to that post, as well as to the original
question. Mistakes happen, and it's no criticism of you just to identify
a mistake you made. There's no reason to get upset about the fact, and
especially none for you to take it out on me.

Try to be reasonable instead.

Pete
 
Ad

Advertisements

P

Paul

LOL

Actually it does not bother me at all...

The only mistake I made was posting a reply to your post rather than put the
post elsewhere which is why I said get off your high horse.

Right now I actually find it amusing that some people on here get so touchy.





Peter Duniho said:
Calm down. We are all trying to help people.

Who's not calm?
[...] so get off your high horse.

Oh, right. You're not calm.

I suggest that you calm down.

It's unfortunate that it bothers you to have posted a reply to my post
that was in fact irrelevant to that post, as well as to the original
question. Mistakes happen, and it's no criticism of you just to identify
a mistake you made. There's no reason to get upset about the fact, and
especially none for you to take it out on me.

Try to be reasonable instead.

Pete
 
Ad

Advertisements


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top