1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.DynamicProxy
.Builder
.CodeBuilder
18 using System
.Reflection
;
20 using Castle
.DynamicProxy
.Builder
.CodeBuilder
.Utils
;
21 using Castle
.DynamicProxy
.Builder
.CodeBuilder
.SimpleAST
;
24 /// Summary description for EasyCallable.
27 public class EasyCallable
: EasyNested
29 private ArgumentReference
[] _args
;
30 private ReturnReferenceExpression _returnType
;
31 private EasyRuntimeMethod _invokeMethod
;
32 private EasyConstructor _constructor
;
33 private EasyMethod _callmethod
;
36 public EasyCallable( AbstractEasyType type
,
38 ReturnReferenceExpression returnType
,
39 params ArgumentReference
[] args
) :
41 String
.Format("__delegate_{0}", id
),
42 typeof(MulticastDelegate
),
43 new Type
[] { typeof(ICallable) }
, returnType
, args
)
47 _returnType
= returnType
;
49 GenerateConstructor();
51 GenerateCallableImplementation();
54 private void GenerateConstructor()
56 ArgumentReference arg1
= new ArgumentReference( typeof(object) );
57 ArgumentReference arg2
= new ArgumentReference( typeof(IntPtr
) );
58 _constructor
= CreateRuntimeConstructor( arg1
, arg2
);
61 private void GenerateInvoke()
63 _invokeMethod
= CreateRuntimeMethod( "Invoke", _returnType
, _args
);
66 private void GenerateCall()
68 ArgumentReference arg
= new ArgumentReference( typeof(object[]) );
69 _callmethod
= CreateMethod( "Call",
70 new ReturnReferenceExpression(typeof(object)), arg
);
72 // LocalReference localRef = method.CodeBuilder.DeclareLocal( typeof(object) );
74 TypeReference
[] dereferencedArguments
= IndirectReference
.WrapIfByRef(_args
);
75 LocalReference
[] localCopies
= new LocalReference
[_args
.Length
];
76 Expression
[] invocationArguments
= new Expression
[_args
.Length
];
78 // Load arguments from the object array.
79 for (int i
= 0; i
< _args
.Length
; i
++)
81 if (_args
[i
].Type
.IsByRef
)
83 localCopies
[i
] = _callmethod
.CodeBuilder
.DeclareLocal(dereferencedArguments
[i
].Type
);
85 _callmethod
.CodeBuilder
.AddStatement(new AssignStatement(localCopies
[i
],
86 new ConvertExpression(dereferencedArguments
[i
].Type
,
87 new LoadRefArrayElementExpression(i
, arg
))));
89 invocationArguments
[i
] = localCopies
[i
].ToAddressOfExpression();
93 invocationArguments
[i
] = new ConvertExpression(dereferencedArguments
[i
].Type
,
94 new LoadRefArrayElementExpression(i
, arg
));
99 MethodInvocationExpression methodInv
= new MethodInvocationExpression(
101 invocationArguments
);
103 Expression result
= null;
104 if (_returnType
.Type
== typeof(void))
106 _callmethod
.CodeBuilder
.AddStatement(new ExpressionStatement(methodInv
));
107 result
= NullExpression
.Instance
;
111 LocalReference resultLocal
= _callmethod
.CodeBuilder
.DeclareLocal(typeof(object));
113 _callmethod
.CodeBuilder
.AddStatement(new AssignStatement(resultLocal
,
114 new ConvertExpression(typeof(object), _returnType
.Type
, methodInv
)));
116 result
= resultLocal
.ToExpression();
119 // Save ByRef arguments into the object array.
120 for (int i
= 0; i
< _args
.Length
; i
++)
122 if (_args
[i
].Type
.IsByRef
)
124 _callmethod
.CodeBuilder
.AddStatement(new AssignArrayStatement(arg
, i
,
125 new ConvertExpression(typeof(object), dereferencedArguments
[i
].Type
,
126 localCopies
[i
].ToExpression())));
131 _callmethod
.CodeBuilder
.AddStatement( new ReturnStatement( result
) );
134 private void GenerateTargetProperty()
136 EasyProperty property
= CreateProperty("Target", typeof(object));
137 EasyMethod getMethod
= property
.CreateGetMethod();
139 MethodInfo baseMethod
= typeof(MulticastDelegate
).GetMethod("get_Target");
141 getMethod
.CodeBuilder
.AddStatement(
142 new ReturnStatement( new MethodInvocationExpression(baseMethod
) ) );
144 // PropertyAttributes patts = PropertyAttributes.None;
145 // PropertyBuilder pbuilder = _delegateBuilder.DefineProperty("Target", patts, typeof(Object), null);
147 // MethodAttributes atts = MethodAttributes.Public|MethodAttributes.Virtual|MethodAttributes.SpecialName;
148 // MethodBuilder methodBuilder = _delegateBuilder.DefineMethod("get_Target",
149 // atts, CallingConventions.Standard, typeof(object), new Type[0]);
151 // ILGenerator gen = methodBuilder.GetILGenerator();
153 // gen.DeclareLocal( typeof(object) );
154 // gen.Emit(OpCodes.Ldarg_0);
155 // gen.Emit(OpCodes.Call, typeof(MulticastDelegate).GetMethod("get_Target"));
156 // gen.Emit(OpCodes.Stloc_0);
157 // gen.Emit(OpCodes.Ldloc_0);
158 // gen.Emit(OpCodes.Ret);
160 // pbuilder.SetGetMethod(methodBuilder);
163 private void GenerateCallableImplementation()
166 GenerateTargetProperty();
174 public EasyMethod InvokeMethod
176 get { return _invokeMethod; }
179 public EasyMethod Callmethod
181 get { return _callmethod; }
184 public ConstructorInfo Constructor
186 get { return _constructor.Builder; }