<feed version="0.3" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns="http://purl.org/atom/ns#" xml:lang="en-US"><title>Teddy's Blog</title><link rel="alternate" type="text/html" href="http://www.dotnetjunkies.com/WebLog/teddy/default.aspx" /><tagline type="text/html">- Sharing my ideas...</tagline><id>http://www.dotnetjunkies.com/WebLog/teddy/default.aspx</id><author><url>http://www.dotnetjunkies.com/WebLog/teddy/default.aspx</url></author><generator url="http://communityserver.org" version="1.0.1.50214">Community Server</generator><modified>2007-11-23T22:01:00Z</modified><entry><title>High performance non-generic wrapper for generic class and method</title><link rel="alternate" type="text/html" href="http://www.dotnetjunkies.com/WebLog/teddy/archive/2007/11/24/378984.aspx" /><id>58df7014-fd75-437c-9641-150997716d1c:378984</id><created>2007-11-23T23:36:00Z</created><content type="text/html" mode="escaped">&lt;p&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attachments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.cnblogs.com/Files/teddyma/GenericMethodWrapperSample.zip"&gt;Download related source code of this post&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;　&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some time, generic is an elegant and useful tool but never all the time&lt;/p&gt;
&lt;p&gt;* When you feel generic programming is so attractive. And you are trying&lt;/p&gt;
&lt;p&gt;to write more and more your code as generic, please slow down a little, &lt;/p&gt;
&lt;p&gt;and do some thinking. &lt;/p&gt;
&lt;p&gt;- Do you really need so many generic classes/methods? &lt;/p&gt;
&lt;p&gt;- Are you trapping yourself? &lt;/p&gt;
&lt;p&gt;- Or, at least, have you consider writing some non-generic wrappers for &lt;/p&gt;
&lt;p&gt;your generic components?&lt;/p&gt;
&lt;p&gt;　&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why you need a non-generic wrapper for generic code?&lt;/p&gt;
&lt;p&gt;* Your writing component depends on calling another generic component, &lt;/p&gt;
&lt;p&gt;but you don't want to publish your component as generic or you want to &lt;/p&gt;
&lt;p&gt;publish your component with different generic parameter types from the &lt;/p&gt;
&lt;p&gt;called component. And you don't want to lose much performance.&lt;/p&gt;
&lt;p&gt;　&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;** Class initialization and method calling by Reflection generally is 
performance &lt;/p&gt;
&lt;p&gt;killer, so I'll not provide any reflection solutions here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1: Generic class initialization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;* Background:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You are writing class B calling generic class A, and you want to initialize
&lt;/p&gt;
&lt;p&gt;an instance of A.&lt;/p&gt;

&lt;pre&gt;
class A
{
	public void Foo()
	{
		//do something according to T
	}
}
class B
{
	public void Foo(Type type)
	{
		//How to call new A().Foo() using type as  here
		//...
	}
}
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;* Solution: &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Convert a generic class initialization problem to a generic method calling 
problem.&lt;/p&gt;


&lt;pre&gt;
class B
{
	public void Foo(Type type)
	{
		//Please go to Case 2 to see how to call B.Foo() using type as  here
		//...
	}
	public void Foo()
	{
		new A().Foo();
	}
}
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Case 2: Simple generic method calling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;* Background:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You are writing class B's non-generic method Foo(Type type) calling a generic 
method &lt;/p&gt;
&lt;p&gt;Foo().&lt;/p&gt;
&lt;pre&gt;
class B
{
	public void Foo(Type type)
	{
		//How to call B.Foo() using type as  here
		//...
	}
	public void Foo()
	{
		//do something according to T
	}
}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;* Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;- If 's possible value can be known at design time, we can use some 
if-else.&lt;/p&gt;
&lt;pre&gt;
public void Foo(Type type)
{
	if (type == typeof(A))
	{
		Foo&lt;A&gt;();
	}
	else ...
}
&lt;/pre&gt;
&lt;p&gt;- Or, if 's possible value can only be known at runtime, or, although they 
can be known&lt;/p&gt;
&lt;p&gt;at design time, but the amount of types are impossible to be enumerated up, 
we can try to&lt;/p&gt;
&lt;p&gt;use DynamicMethod to emit non-reflection generic method calling code, 
because at the &lt;/p&gt;
&lt;p&gt;time you construct the DynamicMethod, you should always know what the type 
parameter is.&lt;/p&gt;
&lt;p&gt;Use DynamicMethodFactory class encapsulating this kind of DynamicMethod 
construction &lt;/p&gt;
&lt;p&gt;which can return a delegate for the DynamicMethod. (The source code of this 
component &lt;/p&gt;
&lt;p&gt;is attached with the sample code. Please see more info of this component in 
the reference &lt;/p&gt;
&lt;p&gt;section.)&lt;/p&gt;
&lt;pre&gt;
public void Foo(Type type)
{
	//find the generic method you want to call
	MethodInfo mi = typeof(B).GetMethod("Foo", Type.EmptyTypes);
	//create the delegate by method info and generic parameter type
	DynamicMethodProxyHandler handler = new DynamicMethodFactory().GetMethodDelegate(mi, type);
	//invoke the method through delegate
	handler(this, null);
}
&lt;/pre&gt;
&lt;p&gt;You can see, this solution is general and the performance is similar to 
invoke Foo&lt;A&gt;() directly.&lt;/p&gt;
&lt;p&gt;The details of the DynamicMethod ILs emitted by the factory class is just 
like "invoke Foo&lt;A&gt;() &lt;/p&gt;
&lt;p&gt;directly".&lt;/p&gt;
&lt;p&gt;This is a very simple generic method, so now I guess you are looking forward 
to more complex ones?&lt;/p&gt;
&lt;p&gt;Let's go on! BTW, how complex to you want? :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 3: Complex generic method calling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;* Background:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now in non-generic class D, let's wrap the calling to a very complex generic 
method ComplexFoo() of&lt;/p&gt;
&lt;p&gt;Class C, ComplexFoo() has input, ref, output parameters and return value. And 
it has two generic&lt;/p&gt;
&lt;p&gt;parameter types.&lt;/p&gt;
&lt;pre&gt;
class C
{
	public string ComplexFoo&amp;lt;T1, T2&amp;gt;(string inputStr, ref int refInt, out int outInt)
	{
		refInt++;
		string retStr = string.Format("{0}, {1}, {2}", typeof(T1), typeof(T2), refInt);
		outInt = retStr.Length;
		return retStr;
	}
}
class D
{
	public string ComplexFoo(Type t1, Type t2, string inputStr, ref int refInt, out int outInt)
	{
		//How to call new C().ComplexFoo&amp;lt;T1, T2&amp;gt;(string inputStr, ref int refInt, out int outInt)?
		//...
	}
}
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;* Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;- Use DynamicMethodFactory.&lt;/p&gt;
&lt;pre&gt;
class D
{
	public string ComplexFoo(Type t1, Type t2, string inputStr, ref int refInt, out int outInt)
	{
		//find the generic method you want to invoke
		MethodInfo mi = typeof(C).GetMethod("ComplexFoo");
		//create the delegate by method info and generic parameter types
		DynamicMethodProxyHandler handler = new DynamicMethodFactory().GetMethodDelegate(mi, t1, t2);
		//invoke the method through delegate
		object[] paramValues = new object[3];
		paramValues[0] = inputStr;
		paramValues[1] = refInt;
		//paramValues[2] is null to contain the out parameter value
		string retStr = (string)handler(this, paramValues);
		refInt = (int)paramValues[1]; //get the ref parameter value after invoke
		outInt = (int)paramValues[2]; //get the output parameter value after invoke
		return retStr;
	}
}
&lt;/pre&gt;
&lt;p&gt;As you can see, the DynamicMethod delegate created by the factory class 
supports all kinds of method &lt;/p&gt;
&lt;p&gt;parameter types and any number of generic parameter types.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Do you think it is useful?&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;* What is NBear.Common, where comes it?&lt;/p&gt;
&lt;p&gt;The NBear.Common library here is one of the common components of an open 
source project - NBear's version 4,&lt;/p&gt;
&lt;p&gt;which is under development now.&lt;/p&gt;
&lt;p&gt;Actually, the sample here only demonstrates a piece of the library, even 
hasn't demonstrated all functions&lt;/p&gt;
&lt;p&gt;of the DynamicMethodFactory class.&lt;/p&gt;
&lt;p&gt;You can go into the source code and find "UnitTest" section for more 
introductions for other functions.&lt;/p&gt;
&lt;p&gt;I'll introduce more other interesting things related to this library and the 
NBear project in the further.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Hope you love it! Looking forward to your ideas to make it better.&lt;/p&gt;&lt;img src="http://www.dotnetjunkies.com/WebLog/aggbug.aspx?PostID=378984" width="1" height="1"&gt;</content><slash:comments>500</slash:comments><wfw:commentRss>http://www.dotnetjunkies.com/WebLog/teddy/commentrss.aspx?PostID=378984</wfw:commentRss></entry><entry><title>The new beginning!</title><link rel="alternate" type="text/html" href="http://www.dotnetjunkies.com/WebLog/teddy/archive/2007/11/23/378442.aspx" /><id>58df7014-fd75-437c-9641-150997716d1c:378442</id><created>2007-11-23T14:01:00Z</created><content type="text/html" mode="escaped">Today, I cleared all old data in this blog. It is a new beginning! I'll continue sharing my ideas here with you all...&lt;br&gt;&lt;img src="http://www.dotnetjunkies.com/WebLog/aggbug.aspx?PostID=378442" width="1" height="1"&gt;</content><slash:comments>0</slash:comments><wfw:commentRss>http://www.dotnetjunkies.com/WebLog/teddy/commentrss.aspx?PostID=378442</wfw:commentRss></entry></feed>