How to get instance of extended object at runtime
I'm not even sure the title correctly explains the situation that I'm running into, but I'll try my best to describe it.
I've got the following classes defined:
public class AccountBase
public class ExtendedAccount1 : AccountBase
public class ExtendedAccount2 : AccountBase
I have a method such as:
Code:
public void AddAccount(AccountBase account)
{
var o = <convert account into actual extended account type> <-- how to do this?
thirdPartyLibrary.DoSomething(o);
}
Somehow in AddAccount, I need to be able to create an instance of the 'account' object as the extended type that was passed in, without having to resort to an if or switch statement to determine what type 'account' actually is.
The reason I need to do this is because third party library that I'm using is only "seeing" AccountBase when I pass in ExtendedAccount1 or ExtendedAccount2. I need it to actually "see" the full extended class.
DoSomething is defined as:
public T DoSomething<T>(
T value
)
I know I can do something like:
Code:
public void AddAccount(AccountBase account)
{
if(account Is ExtendedAccount1)
{
thirdPartyLibrary.DoSomething((ExtendedAccount1)account);
} else if(account Is ExtendedAccount2)
{
thirdPartyLibrary.DoSomething((ExtendedAccount2)account);
}
}
But I REALLY don't want to do this because then I would have to maintain this block of code every time I added a new extended account type. I'm really hoping to make this as generic as possible.
Is this possible? Example code would be greatly appreciated.
Re: How to get instance of extended object at runtime
I assume AccountBase is from the thirdPartyLibrary.
If thirdPartyLibrary is expecting an instance of AccountBase, why do you feel the need to cast "account" to its original type before passing it to thirdPartyLibrary.DoSomething?
Your AddAccount method does not care, so why do you think thirdPartyLibrary.DoSomething will?
Re: How to get instance of extended object at runtime
What if you created overloaded versions of AddAccount? Yeah, it still code that needs to be maintained but, I don't think there is a whole lot that can be done around that. It just comes down to creating code which does type checking (like in the example) ... or an over load wher the type check doesn' need to be done.
-tg
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
TnTinMN
I assume AccountBase is from the thirdPartyLibrary.
If thirdPartyLibrary is expecting an instance of AccountBase, why do you feel the need to cast "account" to its original type before passing it to thirdPartyLibrary.DoSomething?
Your AddAccount method does not care, so why do you think thirdPartyLibrary.DoSomething will?
No. AccountBase is from my code. ThirdPartyLibrary accepts a generic type. The problem is it will only act on the defined type in the code. It is not seeing the extended class properties.
Re: How to get instance of extended object at runtime
Overloading does make it cleaner although I would still like to find a more generic solution.
Re: How to get instance of extended object at runtime
Would using reflection acceptable?
Code:
private void AddAccount(AccountBase b)
{
Type derivedType = b.GetType();
var newInstance = Activator.CreateInstance(derivedType);
ThirdParty tp = new ThirdParty();
tp.DoSomething(newInstance);
}
Re: How to get instance of extended object at runtime
It sounds to me like this DoSomething method may be poorly written in the first place. As for you, there is no such generic solution possible.
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
dee-u
Would using reflection acceptable?
Code:
private void AddAccount(AccountBase b)
{
Type derivedType = b.GetType();
var newInstance = Activator.CreateInstance(derivedType);
ThirdParty tp = new ThirdParty();
tp.DoSomething(newInstance);
}
That won't help because then you have a new instance instead of the original one and also the 'newInstance' variable is type Object, which is even worse than type AccountBase.
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
dee-u
Would using reflection acceptable?
I think dee-u has the right idea, just not the implementation.
Code:
public void AddAccount(AccountBase account)
{
Type accountType = account.GetType();
// assumes DoSomeThing is static if not mi will need to be changed appropriately and change the invoke to use an instance
MethodInfo mi = typeof(ThirdParty).GetMethod("DoSomeThing", BindingFlags.Static | BindingFlags.Public);
MethodInfo genMI = mi.MakeGenericMethod(accountType);
genMI.Invoke(null, new object[] { account });
}
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
TnTinMN
I think dee-u has the right idea, just not the implementation.
Code:
public void AddAccount(AccountBase account)
{
Type accountType = account.GetType();
// assumes DoSomeThing is static if not mi will need to be changed appropriately and change the invoke to use an instance
MethodInfo mi = typeof(ThirdParty).GetMethod("DoSomeThing", BindingFlags.Static | BindingFlags.Public);
MethodInfo genMI = mi.MakeGenericMethod(accountType);
genMI.Invoke(null, new object[] { account });
}
Cool!
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
TnTinMN
I think dee-u has the right idea, just not the implementation.
Code:
public void AddAccount(AccountBase account)
{
Type accountType = account.GetType();
// assumes DoSomeThing is static if not mi will need to be changed appropriately and change the invoke to use an instance
MethodInfo mi = typeof(ThirdParty).GetMethod("DoSomeThing", BindingFlags.Static | BindingFlags.Public);
MethodInfo genMI = mi.MakeGenericMethod(accountType);
genMI.Invoke(null, new object[] { account });
}
This looks promising! However, doSomething is not static. Can you please give me the revised code for non static? Also, DoSomething returns a long which I need access to.
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
softwareguy74
This looks promising! However, doSomething is not static. Can you please give me the revised code for non static? Also, DoSomething returns a long which I need access to.
I just seen your message. The original reflection code was written around this signature:
Code:
public class ThirdParty
{
public static void DoSomeThing<T>(T value)
{
Console.WriteLine(typeof(T).ToString());
}
}
Can I provide another version? Probably, but my brain is mush right now and I need to go move some snow. So it will have to be later this evening.
I really hate to make anymore assumptions so please provide me with the class and method signature. Possibly something like one of these?
Code:
public class ThirdPartyV2a
{
public long DoSomething<T>(T value)
{
Console.WriteLine(typeof(T).ToString());
return new long(); // placeholder
}
}
public class ThirdPartyV2b<T>
{
public long DoSomething(T value)
{
Console.WriteLine(typeof(T).ToString());
return new long(); // placeholder
}
}
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
softwareguy74
This looks promising! However, doSomething is not static. Can you please give me the revised code for non static? Also, DoSomething returns a long which I need access to.
How about you use a bit of logic and do it yourself instead? That code specifies a BindingFlags value of Static, the meaning of which should be obviously. If you don't want to invoke a static method then you'd use a different value. Have you read the documentation for the BindingFlags enumeration to see what values are available? Have you maybe just used Intellisense to list them? You want to invoke an instance method rather than a static method so that's a huge clue right there.
If you've also read the documentation for the MethodInfo.Invoke method, which you should have by now if you don't already know how it works, then you know that you pass the object to invoke the method on as the first argument. If I'm not mistaken, that's all the changes you need to make. Pretty simple stuff if you actually try.
Re: How to get instance of extended object at runtime
Quote:
Originally Posted by
TnTinMN
I just seen your message. The original reflection code was written around this signature:
Code:
public class ThirdParty
{
public static void DoSomeThing<T>(T value)
{
Console.WriteLine(typeof(T).ToString());
}
}
Can I provide another version? Probably, but my brain is mush right now and I need to go move some snow. So it will have to be later this evening.
I really hate to make anymore assumptions so please provide me with the class and method signature. Possibly something like one of these?
Code:
public class ThirdPartyV2a
{
public long DoSomething<T>(T value)
{
Console.WriteLine(typeof(T).ToString());
return new long(); // placeholder
}
}
public class ThirdPartyV2b<T>
{
public long DoSomething(T value)
{
Console.WriteLine(typeof(T).ToString());
return new long(); // placeholder
}
}
The ThirdParty method signatures I'm interested in are:
public int DoSomething1<T>(
long primaryKey
)
where T: class, new()
public T DoSomething2<T>(
T value
)
where T: class, new()
public T DoSomething3<T>(
long primaryKey
)
where T: class, new()
Re: How to get instance of extended object at runtime
jmcilhinney made a very good point that you should have by now looked at the documentation on the reflection methods that I have shown previously and the guidance he provided is accurate, but missing some key caveats. So, on thinking this over a bit, I realized that I am not doing you any favor by providing you a cut and paste solution that you probably do not understand, but rather I am going to raise the concerns that need to be expressed when using Reflection.
The GetMethod method can raise various exceptions, but the one that can bite you the most is the AmbiguousMatchException. Reflection is probing the assembly apply the criteria you provide it and if the criteria is not specific enough, it can find multiple signature that match that criteria. For this reason it is safer to use the GetMethods method and then step through each returned method applying the specific criteria you need. This becomes more important when hacking into generics because as far as I know there is no way to specify all the possible criteria need to confirm an exact method signature match without inspection the various properties on the MethodInfo object. This becomes even more important when using a third party assembly as you are. The code you use may work now, but you have no way of knowing that a future release will not add an overload that makes your current filtering criteria ambiguous.
At a minimum you should be checks the MethodInfo.GetGenericArguments (an array of the possible Generic Parameter types) against the MethodInfo.GetParameters array to make sure there is agreement on those generic type definition and/or your expected passed argument types.
The reason I am so paranoid about making these checks is because when using Reflection to invoke a method, you are bypassing the checks that the compiler would normally make for you; hence you have assumed responsibility to make sure everything matches and will not throw a run-time error.
So, study a bit and make an attempt. If you run into issues, you can always post a specific question and either I or someone else will try to help.