New tests, update
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
index ff426f73d80f8f09c9547614a5010075518a03d1..421e0da03050f8f15e16a3d6148090509b048a67 100644 (file)
@@ -41,8 +41,11 @@ using System.Web.UI.WebControls;
 using System.Web.Util;
 using System.ComponentModel.Design.Serialization;
 #if NET_2_0
+using System.Configuration;
 using System.Collections.Specialized;
+using System.Collections.Generic;
 using System.Text.RegularExpressions;
+using System.Web.Configuration;
 #endif
 
 namespace System.Web.Compilation
@@ -61,7 +64,8 @@ namespace System.Web.Compilation
                internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
                
 #if NET_2_0
-               static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled);
+               static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+               static Regex bindRegexInValue = new Regex (@"Bind\s*\(""(.*?)""\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
 #endif
 
                public TemplateControlCompiler (TemplateControlParser parser)
@@ -77,22 +81,33 @@ namespace System.Web.Compilation
                }
 
                void CreateField (ControlBuilder builder, bool check)
-               {
+               {                       
+                       if (builder == null || builder.ID == null || builder.ControlType == null)
+                               return;
 #if NET_2_0
                        if (partialNameOverride [builder.ID] != null)
                                return;
 #endif
+
+                       MemberAttributes ma = MemberAttributes.Family;
                        currentLocation = builder.location;
-                       if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType))
+                       if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType, ref ma))
                                return; // The field or property already exists in a base class and is accesible.
 
                        CodeMemberField field;
                        field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
-                       field.Attributes = MemberAttributes.Family;
-                       mainClass.Members.Add (field);
+                       field.Attributes = ma;
+#if NET_2_0
+                       field.Type.Options |= CodeTypeReferenceOptions.GlobalReference;
+
+                       if (partialClass != null)
+                               partialClass.Members.Add (field);
+                       else
+#endif
+                               mainClass.Members.Add (field);
                }
 
-               bool CheckBaseFieldOrProperty (string id, Type type)
+               bool CheckBaseFieldOrProperty (string id, Type type, ref MemberAttributes ma)
                {
                        FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
 
@@ -112,10 +127,15 @@ namespace System.Web.Compilation
                                return false;
 
                        if (!other.IsAssignableFrom (type)) {
+#if NET_2_0
+                               ma |= MemberAttributes.New;
+                               return false;
+#else
                                string msg = String.Format ("The base class includes the field '{0}', but its " +
                                                            "type '{1}' is not compatible with {2}",
                                                            id, other, type);
                                throw new ParseException (currentLocation, msg);
+#endif
                        }
 
                        return true;
@@ -152,9 +172,13 @@ namespace System.Web.Compilation
                        /* in the case this is the __BuildControlTree
                         * method, allow subclasses to insert control
                         * specific code. */
-                       if (builder is RootBuilder)
+                       if (builder is RootBuilder) {
+#if NET_2_0
+                               SetCustomAttributes (method);
+#endif
                                AddStatementsToInitMethod (method);
-
+                       }
+                       
                        if (builder.HasAspCode) {
                                CodeMemberMethod renderMethod = new CodeMemberMethod ();
                                builder.renderMethod = renderMethod;
@@ -173,14 +197,8 @@ namespace System.Web.Compilation
                        
                        if (childrenAsProperties || builder.ControlType == null) {
                                string typeString;
-                               if (builder is RootBuilder) {
-#if NET_2_0
-                                       if (parser.IsPartial)
-                                               typeString = parser.PartialClassName;
-                                       else
-#endif
-                                               typeString = parser.ClassName;
-                               }
+                               if (builder is RootBuilder)
+                                       typeString = parser.ClassName;
                                else {
                                        if (builder.ControlType != null && builder.isProperty &&
                                            !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
@@ -234,6 +252,24 @@ namespace System.Web.Compilation
                                }
 
 #if NET_2_0
+                               if (builder.ParentTemplateBuilder is System.Web.UI.WebControls.ContentBuilderInternal) {
+                                       PropertyInfo pi;
+
+                                       try {
+                                               pi = type.GetProperty ("TemplateControl");
+                                       } catch (Exception) {
+                                               pi = null;
+                                       }
+
+                                       if (pi != null && pi.CanWrite) {
+                                               // __ctrl.TemplateControl = this;
+                                               assign = new CodeAssignStatement ();
+                                               assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
+                                               assign.Right = thisRef;
+                                               method.Statements.Add (assign);
+                                       }
+                               }
+                               
                                // _ctrl.SkinID = $value
                                // _ctrl.ApplyStyleSheetSkin (this);
                                //
@@ -259,6 +295,14 @@ namespace System.Web.Compilation
                                }
 #endif
 
+                               // process ID here. It should be set before any other attributes are
+                               // assigned, since the control code may rely on ID being set. We
+                               // skip ID in CreateAssignStatementsFromAttributes
+                               if (builder.attribs != null) {
+                                       string ctl_id = builder.attribs ["id"] as string;
+                                       if (ctl_id != null && ctl_id != String.Empty)
+                                               CreateAssignStatementFromAttribute (builder, "id");
+                               }
 #if NET_2_0
                                if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
                                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
@@ -324,20 +368,40 @@ namespace System.Web.Compilation
 
                                        // this is the bit that causes the following stuff to end up in the else { }
                                        builder.methodStatements = condStatement.FalseStatements;
-
-                                       // __ctrl.TemplateControl = this;
-                                       assign = new CodeAssignStatement ();
-                                       assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
-                                       assign.Right = thisRef;
-
-                                       method.Statements.Add (assign);
                                }
 #endif
                        }
-
+                       
                        mainClass.Members.Add (method);
                }
 
+#if NET_2_0
+               void SetCustomAttribute (CodeMemberMethod method, UnknownAttributeDescriptor uad)
+               {
+                       CodeAssignStatement assign = new CodeAssignStatement ();
+                       assign.Left = new CodePropertyReferenceExpression (
+                               new CodeArgumentReferenceExpression("__ctrl"),
+                               uad.Info.Name);
+                       assign.Right = GetExpressionFromString (uad.Value.GetType (), uad.Value.ToString (), uad.Info);
+                       
+                       method.Statements.Add (assign);
+               }
+               
+               void SetCustomAttributes (CodeMemberMethod method)
+               {
+                       Type baseType = parser.BaseType;
+                       if (baseType == null)
+                               return;
+                       
+                       List <UnknownAttributeDescriptor> attrs = parser.UnknownMainAttributes;
+                       if (attrs == null || attrs.Count == 0)
+                               return;
+
+                       foreach (UnknownAttributeDescriptor uad in attrs)
+                               SetCustomAttribute (method, uad);
+               }
+#endif
+               
                protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
                {
                }
@@ -374,14 +438,16 @@ namespace System.Web.Compilation
 #if NET_2_0
                        bool need_if = false;
                        value = value.Trim ();
-                       if (StrUtils.StartsWith (value, "Bind")) {
-                               value = "Eval" + value.Substring (4);
-                               need_if = true;
+                       if (StrUtils.StartsWith (value, "Bind", true)) {
+                               Match match = bindRegexInValue.Match (value);
+                               if (match.Success) {
+                                       value = "Eval" + value.Substring (4);
+                                       need_if = true;
+                               }
                        }
 #endif
-
                        method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
-
+                       
                        CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
 
                        // This should be a CodePropertyReferenceExpression for properties... but it works anyway
@@ -402,7 +468,7 @@ namespace System.Web.Compilation
                        CodeAssignStatement assign = new CodeAssignStatement (field, expr);
 #if NET_2_0
                        if (need_if) {
-                               CodeExpression page = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Page");
+                               CodeExpression page = new CodePropertyReferenceExpression (thisRef, "Page");
                                CodeExpression left = new CodeMethodInvokeExpression (page, "GetDataItem");
                                CodeBinaryOperatorExpression ce = new CodeBinaryOperatorExpression (left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
                                CodeConditionStatement ccs = new CodeConditionStatement (ce, assign);
@@ -416,15 +482,22 @@ namespace System.Web.Compilation
                        return method.Name;
                }
 
-               void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound)
-               {
+               void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound, bool isExpression)
+               {                       
                        CodeMemberMethod method = builder.method;
-                       if (isDataBound && IsWritablePropertyOrField (member)) {
+                       bool isWritable = IsWritablePropertyOrField (member);
+                       if (isDataBound && isWritable) {
                                string dbMethodName = DataBoundProperty (builder, type, var_name, att);
                                AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
                                return;
                        }
-
+#if NET_2_0
+                       else if (isExpression && isWritable) {
+                               AddExpressionAssign (method, member, type, var_name, att);
+                               return;
+                       }
+#endif
+                       
                        CodeAssignStatement assign = new CodeAssignStatement ();
                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
                        currentLocation = builder.location;
@@ -443,11 +516,19 @@ namespace System.Web.Compilation
                }
 
 #if NET_2_0
+               bool IsExpression (string value)
+               {
+                       if (value == null || value == "")
+                               return false;
+                       string str = value.Trim ();
+                       return (StrUtils.StartsWith (str, "<%$") && StrUtils.EndsWith (str, "%>"));
+               }               
+
                void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
                {
                        string str = value.Trim ();
                        str = str.Substring (3).Trim ();        // eats "<%#"
-                       if (StrUtils.StartsWith (str, "Bind")) {
+                       if (StrUtils.StartsWith (str, "Bind", true)) {
                                Match match = bindRegex.Match (str);
                                if (match.Success) {
                                        string bindingName = match.Groups [1].Value;
@@ -507,12 +588,16 @@ namespace System.Web.Compilation
                }
 
                bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
-                                               string attValue, string prefix)
+                                                string attValue, string prefix)
                {
                        int hyphen = id.IndexOf ('-');
                        bool isPropertyInfo = (member is PropertyInfo);
                        bool isDataBound = IsDataBound (attValue);
-
+#if NET_2_0
+                       bool isExpression = !isDataBound && IsExpression (attValue);
+#else
+                       bool isExpression = false;
+#endif
                        Type type;
                        if (isPropertyInfo) {
                                type = ((PropertyInfo) member).PropertyType;
@@ -522,12 +607,14 @@ namespace System.Web.Compilation
 
                        if (InvariantCompareNoCase (member.Name, id)) {
 #if NET_2_0
-                               if (isDataBound) RegisterBindingInfo (builder, member.Name, ref attValue);
+                               if (isDataBound)
+                                       RegisterBindingInfo (builder, member.Name, ref attValue);
+                               
 #endif
                                if (!IsWritablePropertyOrField (member))
                                        return false;
 
-                               AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound);
+                               AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound, isExpression);
                                return true;
                        }
                        
@@ -537,6 +624,7 @@ namespace System.Web.Compilation
                        string prop_field = id.Replace ("-", ".");
                        string [] parts = prop_field.Split (new char [] {'.'});
                        int length = parts.Length;
+                       
                        if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
                                return false;
 
@@ -545,7 +633,7 @@ namespace System.Web.Compilation
                                if (sub_member == null)
                                        return false;
 
-                               string new_prefix = prefix + parts [0] + ".";
+                               string new_prefix = prefix + member.Name + ".";
                                string new_id = id.Substring (hyphen + 1);
                                return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
                        }
@@ -569,12 +657,158 @@ namespace System.Web.Compilation
                        if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
 #endif
                        AddCodeForPropertyOrField (builder, subprop.PropertyType,
-                                               prefix + member.Name + "." + subprop.Name,
-                                               val, subprop, isDataBound);
+                                                  prefix + member.Name + "." + subprop.Name,
+                                                  val, subprop, isDataBound, isExpression);
 
                        return true;
                }
 
+#if NET_2_0
+               void AddExpressionAssign (CodeMemberMethod method, MemberInfo member, Type type, string name, string value)
+               {
+                       CodeAssignStatement assign = new CodeAssignStatement ();
+                       assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
+
+                       // First let's find the correct expression builder
+                       string expr = value.Substring (3, value.Length - 5).Trim ();
+                       int colon = expr.IndexOf (':');
+                       if (colon == -1)
+                               return;
+                       string prefix = expr.Substring (0, colon).Trim ();
+                       
+                       System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration ("");
+                       if (config == null)
+                               return;
+                       CompilationSection cs = (CompilationSection)config.GetSection ("system.web/compilation");
+                       if (cs == null)
+                               return;
+                       if (cs.ExpressionBuilders == null || cs.ExpressionBuilders.Count == 0)
+                               return;
+
+                       System.Web.Configuration.ExpressionBuilder ceb = cs.ExpressionBuilders[prefix];
+                       if (ceb == null)
+                               return;
+                       string builderType = ceb.Type;
+
+                       Type t;
+                       try {
+                               t = HttpApplication.LoadType (builderType, true);
+                       } catch (Exception e) {
+                               throw new HttpException (
+                                       String.Format ("Failed to load expression builder type `{0}'", builderType), e);
+                       }
+
+                       if (!typeof (System.Web.Compilation.ExpressionBuilder).IsAssignableFrom (t))
+                               throw new HttpException (
+                                       String.Format (
+                                               "Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder",
+                                               builderType));
+
+                       System.Web.Compilation.ExpressionBuilder eb = null;
+                       object parsedData;
+                       ExpressionBuilderContext ctx;
+                       
+                       try {
+                               eb = Activator.CreateInstance (t) as System.Web.Compilation.ExpressionBuilder;
+                               ctx = new ExpressionBuilderContext (HttpContext.Current.Request.FilePath);
+                               parsedData = eb.ParseExpression (expr.Substring (colon + 1).Trim (), type, ctx);
+                       } catch (Exception e) {
+                               throw new HttpException (
+                                       String.Format ("Failed to create an instance of type `{0}'", builderType), e);
+                       }
+                       
+                       BoundPropertyEntry bpe = CreateBoundPropertyEntry (member as PropertyInfo, prefix, expr);
+                       assign.Right = eb.GetCodeExpression (bpe, parsedData, ctx);
+                       
+                       method.Statements.Add (assign);
+               }
+
+               BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr)
+               {
+                       if (pi == null)
+                               return null;
+
+                       BoundPropertyEntry ret = new BoundPropertyEntry ();
+                       ret.Expression = expr;
+                       ret.ExpressionPrefix = prefix;
+                       ret.Generated = false;
+                       ret.Name = pi.Name;
+                       ret.PropertyInfo = pi;
+                       ret.Type = pi.PropertyType;
+
+                       return ret;
+               }
+               
+               void AssignPropertyFromResources (CodeMemberMethod method, MemberInfo mi, string attvalue)
+               {
+                       bool isProperty = mi.MemberType == MemberTypes.Property;
+                       bool isField = !isProperty && (mi.MemberType == MemberTypes.Field);
+
+                       if (!isProperty && !isField || !IsWritablePropertyOrField (mi))
+                               return;                 
+
+                       string memberName = mi.Name;
+                       string resname = String.Format ("{0}.{1}", attvalue, memberName);
+
+                       // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
+                       string inputFile = parser.InputFile;
+                       string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
+       
+                       if (StrUtils.StartsWith (inputFile, physPath))
+                               inputFile = parser.InputFile.Substring (physPath.Length - 1);
+                       else
+                               return;
+
+                       char dsc = System.IO.Path.DirectorySeparatorChar;
+                       if (dsc != '/')
+                               inputFile = inputFile.Replace (dsc, '/');
+
+                       object obj = HttpContext.GetLocalResourceObject (inputFile, resname);
+                       if (obj == null)
+                               return;
+
+                       if (!isProperty && !isField)
+                               return; // an "impossible" case
+                       
+                       Type declaringType = mi.DeclaringType;
+                       CodeAssignStatement assign = new CodeAssignStatement ();
+                       
+                       assign.Left = new CodePropertyReferenceExpression (ctrlVar, memberName);
+                       assign.Right = ResourceExpressionBuilder.CreateGetLocalResourceObject (mi, resname);
+                       
+                       method.Statements.Add (assign);
+               }
+
+               void AssignPropertiesFromResources (CodeMemberMethod method, Type controlType, string attvalue)
+               {
+                       // Process all public fields and properties of the control. We don't use GetMembers to make the code
+                       // faster
+                       FieldInfo [] fields = controlType.GetFields (
+                               BindingFlags.Instance | BindingFlags.Static |
+                               BindingFlags.Public | BindingFlags.FlattenHierarchy);
+                       PropertyInfo [] properties = controlType.GetProperties (
+                               BindingFlags.Instance | BindingFlags.Static |
+                               BindingFlags.Public | BindingFlags.FlattenHierarchy);
+
+                       foreach (FieldInfo fi in fields)
+                               AssignPropertyFromResources (method, fi, attvalue);
+                       foreach (PropertyInfo pi in properties)
+                               AssignPropertyFromResources (method, pi, attvalue);
+               }
+               
+               void AssignPropertiesFromResources (ControlBuilder builder, string attvalue)
+               {
+                       if (attvalue == null || attvalue.Length == 0)
+                               return;
+                       
+                       Type controlType = builder.ControlType;
+                       if (controlType == null)
+                               return;
+
+                       AssignPropertiesFromResources (builder.method, controlType, attvalue);
+               }
+#endif
+               
                void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
                {
                        //"__ctrl.{0} += new {1} (this.{2});"
@@ -591,7 +825,7 @@ namespace System.Web.Compilation
                {
                        EventInfo [] ev_info = null;
                        Type type = builder.ControlType;
-
+                       
                        string attvalue = builder.attribs [id] as string;
                        if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
                                if (ev_info == null)
@@ -611,6 +845,13 @@ namespace System.Web.Compilation
 
                        }
 
+#if NET_2_0
+                       if (id.ToLower () == "meta:resourcekey") {
+                               AssignPropertiesFromResources (builder, attvalue);
+                               return;
+                       }
+#endif
+                       
                        int hyphen = id.IndexOf ('-');
                        string alt_id = id;
                        if (hyphen != -1)
@@ -628,6 +869,7 @@ namespace System.Web.Compilation
                        string val;
                        CodeMemberMethod method = builder.method;
                        bool databound = IsDataBound (attvalue);
+
                        if (databound) {
                                val = attvalue.Substring (3);
                                val = val.Substring (0, val.Length - 2);
@@ -649,22 +891,37 @@ namespace System.Web.Compilation
 
                protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
                {
+#if NET_2_0
+                       bool haveMetaKey = false;
+#endif
                        this.dataBoundAtts = 0;
                        IDictionary atts = builder.attribs;
                        if (atts == null || atts.Count == 0)
                                return;
-
+                       
                        foreach (string id in atts.Keys) {
                                if (InvariantCompareNoCase (id, "runat"))
                                        continue;
-
+                               // ID is assigned in BuildControltree
+                               if (InvariantCompareNoCase (id, "id"))
+                                       continue;
+                               
 #if NET_2_0
                                /* we skip SkinID here as it's assigned in BuildControlTree */
                                if (InvariantCompareNoCase (id, "skinid"))
                                        continue;
+                               if (InvariantCompareNoCase (id, "meta:resourcekey")) {
+                                       haveMetaKey = true;
+                                       continue;
+                               }
 #endif
                                CreateAssignStatementFromAttribute (builder, id);
                        }
+                       
+#if NET_2_0
+                       if (haveMetaKey)
+                               CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
+#endif
                }
 
                void CreateDBAttributeMethod (ControlBuilder builder, string attr, string code)
@@ -714,10 +971,15 @@ namespace System.Web.Compilation
 
                protected void AddChildCall (ControlBuilder parent, ControlBuilder child)
                {
+                       if (parent == null || child == null)
+                               return;
                        CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
                        CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
 
-                       object [] atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
+                       object [] atts = null;
+                       
+                       if (child.ControlType != null)
+                               child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
                        if (atts != null && atts.Length > 0) {
                                PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
                                CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
@@ -769,8 +1031,8 @@ namespace System.Web.Compilation
                {
                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
 
-                       CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
-                       newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+                       CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
+                               new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
 
                        CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
                        newCompiled.Parameters.Add (newBuild);
@@ -784,11 +1046,11 @@ namespace System.Web.Compilation
                {
                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
 
-                       CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
-                       newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+                       CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
+                               new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
 
-                       CodeObjectCreateExpression newExtract = new CodeObjectCreateExpression (typeof (ExtractTemplateValuesMethod));
-                       newExtract.Parameters.Add (new CodeMethodReferenceExpression (thisRef, extractMethodName));
+                       CodeDelegateCreateExpression newExtract = new CodeDelegateCreateExpression (
+                               new CodeTypeReference (typeof (ExtractTemplateValuesMethod)), thisRef, extractMethodName);
 
                        CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
                        newCompiled.Parameters.Add (newBuild);
@@ -817,27 +1079,40 @@ namespace System.Web.Compilation
                        CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
                        
                        if (builder.Bindings != null) {
+                               Hashtable hash = new Hashtable ();
                                foreach (TemplateBinding binding in builder.Bindings) {
-                                       CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
-                                       method.Statements.Add (dec);
-                                       CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
-                                       CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
-                                       invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
-                                       
-                                       CodeAssignStatement assign = new CodeAssignStatement ();
-                                       CodeVariableReferenceExpression control = new CodeVariableReferenceExpression (binding.ControlId); 
-                                       assign.Left = control;
-                                       assign.Right = new CodeCastExpression (binding.ControlType, invoke);
-                                       method.Statements.Add (assign);
-                                       
-                                       CodeConditionStatement sif = new CodeConditionStatement ();
-                                       sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
-                                       
+                                       CodeConditionStatement sif;
+                                       CodeVariableReferenceExpression control;
+                                       CodeAssignStatement assign;
+
+                                       if (hash [binding.ControlId] == null) {
+
+                                               CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
+                                               method.Statements.Add (dec);
+                                               CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
+                                               CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
+                                               invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
+
+                                               assign = new CodeAssignStatement ();
+                                               control = new CodeVariableReferenceExpression (binding.ControlId);
+                                               assign.Left = control;
+                                               assign.Right = new CodeCastExpression (binding.ControlType, invoke);
+                                               method.Statements.Add (assign);
+
+                                               sif = new CodeConditionStatement ();
+                                               sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
+
+                                               method.Statements.Add (sif);
+
+                                               hash [binding.ControlId] = sif;
+                                       }
+
+                                       sif = (CodeConditionStatement) hash [binding.ControlId];
+                                       control = new CodeVariableReferenceExpression (binding.ControlId);
                                        assign = new CodeAssignStatement ();
                                        assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
                                        assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
                                        sif.TrueStatements.Add (assign);
-                                       method.Statements.Add (sif);
                                }
                        }
 
@@ -847,8 +1122,8 @@ namespace System.Web.Compilation
 
                void AddContentTemplateInvocation (ContentBuilderInternal cbuilder, CodeMemberMethod method, string methodName)
                {
-                       CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
-                       newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+                       CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
+                               new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
 
                        CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
                        newCompiled.Parameters.Add (newBuild);
@@ -886,7 +1161,9 @@ namespace System.Web.Compilation
                        TemplateBuilder tb = builder as TemplateBuilder;
                        if (tb != null && tb.ContainerType != null)
                                return tb.ContainerType;
-
+#if NET_2_0
+                       return builder.BindingContainerType;
+#else
                        Type type = builder.BindingContainerType;
 
                        PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
@@ -902,6 +1179,7 @@ namespace System.Web.Compilation
                                return type;
 
                        return prop.PropertyType;
+#endif
                }
                
                CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
@@ -988,11 +1266,36 @@ namespace System.Web.Compilation
                {
                        EnsureID (builder);
                        bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
+                       
                        if (!isTemplate && !inTemplate) {
                                CreateField (builder, true);
                        } else if (!isTemplate) {
-                               builder.ID = builder.GetNextID (null);
-                               CreateField (builder, false);
+                               bool doCheck = false;
+                               
+#if NET_2_0
+                               bool singleInstance = false;
+                               ControlBuilder pb = builder.parentBuilder;
+                               TemplateBuilder tpb;
+                               while (pb != null) {
+                                       tpb = pb as TemplateBuilder;
+                                       if (tpb == null) {
+                                               pb = pb.parentBuilder;
+                                               continue;
+                                       }
+                                       
+                                       if (tpb.TemplateInstance == TemplateInstance.Single)
+                                               singleInstance = true;
+                                       break;
+                               }
+                               
+                               if (!singleInstance)
+#endif
+                                       builder.ID = builder.GetNextID (null);
+#if NET_2_0
+                               else
+                                       doCheck = true;
+#endif
+                               CreateField (builder, doCheck);
                        }
 
                        InitMethod (builder, isTemplate, childrenAsProperties);
@@ -1004,7 +1307,6 @@ namespace System.Web.Compilation
 
                                StringBuilder sb = new StringBuilder ();
                                foreach (object b in builder.Children) {
-
                                        if (b is string) {
                                                sb.Append ((string) b);
                                                continue;
@@ -1111,8 +1413,14 @@ namespace System.Web.Compilation
                        
                        if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
                                builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
-               }
 
+#if NET_2_0
+                       if (builder is RootBuilder)
+                               if (!String.IsNullOrEmpty (parser.MetaResourceKey))
+                                       AssignPropertiesFromResources (builder.method, parser.BaseType, parser.MetaResourceKey);
+#endif
+               }
+               
                protected internal override void CreateMethods ()
                {
                        base.CreateMethods ();
@@ -1186,21 +1494,8 @@ namespace System.Web.Compilation
                        }
 
                        CreateApplicationInstance ();
-                       CreateTemplateSourceDirectory ();
-               }
-
-               void CreateTemplateSourceDirectory ()
-               {
-                       CodeMemberProperty prop = new CodeMemberProperty ();
-                       prop.Type = new CodeTypeReference (typeof (string));
-                       prop.Name = "TemplateSourceDirectory";
-                       prop.Attributes = MemberAttributes.Public | MemberAttributes.Override;
-
-                       CodePrimitiveExpression expr = new CodePrimitiveExpression (parser.BaseVirtualDir);
-                       prop.GetStatements.Add (new CodeMethodReturnStatement (expr));
-                       mainClass.Members.Add (prop);
                }
-
+               
                void CreateApplicationInstance ()
                {
                        CodeMemberProperty prop = new CodeMemberProperty ();
@@ -1215,6 +1510,11 @@ namespace System.Web.Compilation
 
                        CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
                        prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
+#if NET_2_0
+                       if (partialClass != null)
+                               partialClass.Members.Add (prop);
+                       else
+#endif
                        mainClass.Members.Add (prop);
                }
 
@@ -1231,9 +1531,13 @@ namespace System.Web.Compilation
                        fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
                        ret.Expression = fldRef;
                        prop.GetStatements.Add (ret);
-                       
                        prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
 
+#if NET_2_0
+                       CodeAttributeDeclaration attr = new CodeAttributeDeclaration ("System.Obsolete");
+                       prop.CustomAttributes.Add (attr);
+#endif
+                       
                        mainClass.Members.Add (prop);
 
                        // Add the __autoHandlers field
@@ -1259,34 +1563,131 @@ namespace System.Web.Compilation
                        return str;
                }
 #endif
-    
-               CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
-               {                       
+
+               TypeConverter GetConverterForMember (MemberInfo member)
+               {
+                       TypeConverterAttribute tca = null;
+                       object[] attrs;
+                       
 #if NET_2_0
-                       Type origType = type;
-                       bool wasNullable = false;
+                       attrs = member.GetCustomAttributes (typeof (TypeConverterAttribute), true);
+                       if (attrs.Length > 0)
+                               tca = attrs [0] as TypeConverterAttribute;
+#else
+                       attrs = member.GetCustomAttributes (true);
                        
+                       foreach (object attr in attrs) {
+                               tca = attr as TypeConverterAttribute;
+                               
+                               if (tca != null)
+                                       break;
+                       }
+#endif
+
+                       if (tca == null)
+                               return null;
+
+                       string typeName = tca.ConverterTypeName;
+                       if (typeName == null || typeName.Length == 0)
+                               return null;
+
+                       Type t = null;
+                       try {
+                               t = HttpApplication.LoadType (typeName);
+                       } catch (Exception) {
+                               // ignore
+                       }
+
+                       if (t == null)
+                               return null;
+
+                       return (TypeConverter) Activator.CreateInstance (t);
+               }
+               
+               CodeExpression CreateNullableExpression (Type type, CodeExpression inst, bool nullable)
+               {
+#if NET_2_0
+                       if (!nullable)
+                               return inst;
+                       
+                       return new CodeObjectCreateExpression (
+                               type,
+                               new CodeExpression[] {inst}
+                       );
+#else
+                       return inst;
+#endif
+               }
+
+               bool SafeCanConvertFrom (Type type, TypeConverter cvt)
+               {
+                       try {
+                               return cvt.CanConvertFrom (type);
+                       } catch (NotImplementedException) {
+                               return false;
+                       }
+               }
+
+               bool SafeCanConvertTo (Type type, TypeConverter cvt)
+               {
+                       try {
+                               return cvt.CanConvertTo (type);
+                       } catch (NotImplementedException) {
+                               return false;
+                       }
+               }
+               
+               CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
+               {
+                       TypeConverter cvt = GetConverterForMember (member);
+                       if (cvt != null && !SafeCanConvertFrom (typeof (string), cvt))
+                               cvt = null;
+
+                       object convertedFromAttr = null;
+                       bool preConverted = false;
+                       if (cvt != null && str != null) {
+                               convertedFromAttr = cvt.ConvertFromInvariantString (str);
+                               if (convertedFromAttr != null) {
+                                       type = convertedFromAttr.GetType ();
+                                       preConverted = true;
+                               }
+                       }
+
+                       bool wasNullable = false;
+                       Type originalType = type;
+#if NET_2_0
                        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
                                Type[] types = type.GetGenericArguments();
+                               originalType = type;
                                type = types[0]; // we're interested only in the first type here
                                wasNullable = true;
                        }
 #endif
-
+                       
                        if (type == typeof (string)) {
+                               if (preConverted)
+                                       return CreateNullableExpression (originalType,
+                                                                        new CodePrimitiveExpression ((string) convertedFromAttr),
+                                                                        wasNullable);
+                               
 #if NET_2_0
                                object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
                                if (urlAttr.Length != 0)
                                        str = HandleUrlProperty (str, member);
 #endif
-                               return new CodePrimitiveExpression (str);
+                               return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
                        }
 
                        if (type == typeof (bool)) {
+                               if (preConverted)
+                                       return CreateNullableExpression (originalType,
+                                                                        new CodePrimitiveExpression ((bool) convertedFromAttr),
+                                                                        wasNullable);
+                               
                                if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
-                                       return new CodePrimitiveExpression (true);
+                                       return CreateNullableExpression (originalType, new CodePrimitiveExpression (true), wasNullable);
                                else if (InvariantCompareNoCase (str, "false"))
-                                       return new CodePrimitiveExpression (false);
+                                       return CreateNullableExpression (originalType, new CodePrimitiveExpression (false), wasNullable);
 #if NET_2_0
                                else if (wasNullable && InvariantCompareNoCase(str, "null"))
                                        return new CodePrimitiveExpression (null);
@@ -1295,72 +1696,86 @@ namespace System.Web.Compilation
                                        throw new ParseException (currentLocation,
                                                        "Value '" + str  + "' is not a valid boolean.");
                        }
-
+                       
                        if (str == null)
                                return new CodePrimitiveExpression (null);
 
                        if (type.IsPrimitive)
-                               return new CodePrimitiveExpression (Convert.ChangeType (str, type, CultureInfo.InvariantCulture));
+                               return CreateNullableExpression (originalType,
+                                                                new CodePrimitiveExpression (
+                                                                        Convert.ChangeType (preConverted ? convertedFromAttr : str,
+                                                                                            type, CultureInfo.InvariantCulture)),
+                                                                wasNullable);
 
                        if (type == typeof (string [])) {
-                               string [] subs = str.Split (',');
+                               string [] subs;
+
+                               if (preConverted)
+                                       subs = (string[])convertedFromAttr;
+                               else
+                                       subs = str.Split (',');
                                CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
                                expr.CreateType = new CodeTypeReference (typeof (string));
-                               foreach (string v in subs) {
+                               foreach (string v in subs)
                                        expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
-                               }
 
-                               return expr;
+                               return CreateNullableExpression (originalType, expr, wasNullable);
                        }
-
-                       if (type == typeof (Color)){
-                               if (colorConverter == null)
-                                       colorConverter = TypeDescriptor.GetConverter (typeof (Color));
-
-                               if (str.Trim().Length == 0) {
-                                       CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
-                                       return new CodeFieldReferenceExpression (ft, "Empty");
-                               }
-                               
+                       
+                       if (type == typeof (Color)) {
                                Color c;
-                               try {
-                                       if (str.IndexOf (',') == -1) {
-                                               c = (Color) colorConverter.ConvertFromString (str);
-                                       } else {
-                                               int [] argb = new int [4];
-                                               argb [0] = 255;
-
-                                               string [] parts = str.Split (',');
-                                               int length = parts.Length;
-                                               if (length < 3)
-                                                       throw new Exception ();
-
-                                               int basei = (length == 4) ? 0 : 1;
-                                               for (int i = length - 1; i >= 0; i--) {
-                                                       argb [basei + i] = (int) Byte.Parse (parts [i]);
-                                               }
-                                               c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
-                                       }
-                               } catch (Exception e){
-                                       // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
-                                       // TypeConverter for Color fails to ConvertFromString.
-                                       // Hence this hack...
-                                       if (InvariantCompareNoCase ("LightGrey", str)) {
-                                               c = Color.LightGray;
-                                       } else {
-                                               throw new ParseException (currentLocation,
-                                                       "Color " + str + " is not a valid color.", e);
+                               
+                               if (!preConverted) {
+                                       if (colorConverter == null)
+                                               colorConverter = TypeDescriptor.GetConverter (typeof (Color));
+                               
+                                       if (str.Trim().Length == 0) {
+                                               CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
+                                               return CreateNullableExpression (originalType,
+                                                                                new CodeFieldReferenceExpression (ft, "Empty"),
+                                                                                wasNullable);
                                        }
-                               }
 
-                               if (c.IsKnownColor){
+                                       try {
+                                               if (str.IndexOf (',') == -1) {
+                                                       c = (Color) colorConverter.ConvertFromString (str);
+                                               } else {
+                                                       int [] argb = new int [4];
+                                                       argb [0] = 255;
+
+                                                       string [] parts = str.Split (',');
+                                                       int length = parts.Length;
+                                                       if (length < 3)
+                                                               throw new Exception ();
+
+                                                       int basei = (length == 4) ? 0 : 1;
+                                                       for (int i = length - 1; i >= 0; i--) {
+                                                               argb [basei + i] = (int) Byte.Parse (parts [i]);
+                                                       }
+                                                       c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
+                                               }
+                                       } catch (Exception e) {
+                                               // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
+                                               // TypeConverter for Color fails to ConvertFromString.
+                                               // Hence this hack...
+                                               if (InvariantCompareNoCase ("LightGrey", str)) {
+                                                       c = Color.LightGray;
+                                               } else {
+                                                       throw new ParseException (currentLocation,
+                                                                                 "Color " + str + " is not a valid color.", e);
+                                               }
+                                       }
+                               } else
+                                       c = (Color)convertedFromAttr;
+                               
+                               if (c.IsKnownColor) {
                                        CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
                                        if (c.IsSystemColor)
                                                type = typeof (SystemColors);
 
                                        expr.TargetObject = new CodeTypeReferenceExpression (type);
                                        expr.FieldName = c.Name;
-                                       return expr;
+                                       return CreateNullableExpression (originalType, expr, wasNullable);
                                } else {
                                        CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
                                        m.TargetObject = new CodeTypeReferenceExpression (type);
@@ -1370,22 +1785,29 @@ namespace System.Web.Compilation
                                        invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
                                        invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
                                        invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
-                                       return invoke;
+                                       return CreateNullableExpression (originalType, invoke, wasNullable);
                                }
                        }
 
-                       TypeConverter converter = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
-                       
-                       if (converter != null && converter.CanConvertFrom (typeof (string))) {
-                               object value = converter.ConvertFrom (str);
+                       TypeConverter converter = preConverted ? cvt :
+                               wasNullable ? TypeDescriptor.GetConverter (type) :
+                               TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
+
+                       if (preConverted || (converter != null && SafeCanConvertFrom (typeof (string), converter))) {
+                               object value = preConverted ? convertedFromAttr : converter.ConvertFromInvariantString (str);
 
-                               if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
+                               if (SafeCanConvertTo (typeof (InstanceDescriptor), converter)) {
                                        InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
-                                       return GenerateInstance (idesc, true);
+                                       if (wasNullable)
+                                               return CreateNullableExpression (originalType, GenerateInstance (idesc, true),
+                                                                                wasNullable);
+                                       
+                                       return new CodeCastExpression (type, GenerateInstance (idesc, true));
                                }
 
                                CodeExpression exp = GenerateObjectInstance (value, false);
-                               if (exp != null) return exp;
+                               if (exp != null)
+                                       return CreateNullableExpression (originalType, exp, wasNullable);
                                
                                CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
                                m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
@@ -1397,12 +1819,15 @@ namespace System.Web.Compilation
                                invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
                                invoke.Parameters.Add (new CodePrimitiveExpression (str));
 
-                               return new CodeCastExpression (tref, invoke);
+                               if (wasNullable)
+                                       return CreateNullableExpression (originalType, invoke, wasNullable);
+                               
+                               return new CodeCastExpression (type, invoke);
                        }
-                       
-                       Console.WriteLine ("Unknown type: " + type + " value: " + str);
 
-                       return new CodePrimitiveExpression (str);
+                       Console.WriteLine ("Unknown type: " + type + " value: " + str);
+                       
+                       return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
                }
                
                CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
@@ -1439,11 +1864,17 @@ namespace System.Web.Compilation
                {
                        if (value == null)
                                return new CodePrimitiveExpression (null);
+
+                       if (value is System.Type) {
+                               CodeTypeReference tref = new CodeTypeReference (value.ToString ());
+                               return new CodeTypeOfExpression (tref);
+                       }
                        
-                       Type t = value.GetType();
+                       Type t = value.GetType ();
+
                        if (t.IsPrimitive || value is string)
                                return new CodePrimitiveExpression (value);
-                               
+                       
                        if (t.IsArray) {
                                Array ar = (Array) value;
                                CodeExpression[] items = new CodeExpression [ar.Length];
@@ -1474,14 +1905,41 @@ namespace System.Web.Compilation
                {
                        if (value is System.Web.UI.WebControls.Unit) {
                                System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
-                               MethodInfo met = typeof(System.Web.UI.WebControls.Unit).GetMethod ("Parse", new Type[] {typeof(string)});
-                               return new InstanceDescriptor (met, new object[] {s.ToString ()});
+                               ConstructorInfo c = typeof(System.Web.UI.WebControls.Unit).GetConstructor (
+                                       BindingFlags.Instance | BindingFlags.Public,
+                                       null,
+                                       new Type[] {typeof(double), typeof(System.Web.UI.WebControls.UnitType)},
+                                       null);
+                               
+                               return new InstanceDescriptor (c, new object[] {s.Value, s.Type});
                        }
                        
                        if (value is System.Web.UI.WebControls.FontUnit) {
                                System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
-                               MethodInfo met = typeof(System.Web.UI.WebControls.FontUnit).GetMethod ("Parse", new Type[] {typeof(string)});
-                               return new InstanceDescriptor (met, new object[] {s.ToString ()});
+
+                               Type cParamType = null;
+                               object cParam = null;
+
+                               switch (s.Type) {
+                                       case FontSize.AsUnit:
+                                       case FontSize.NotSet:
+                                               cParamType = typeof (System.Web.UI.WebControls.Unit);
+                                               cParam = s.Unit;
+                                               break;
+
+                                       default:
+                                               cParamType = typeof (string);
+                                               cParam = s.Type.ToString ();
+                                               break;
+                               }
+                               
+                               ConstructorInfo c = typeof(System.Web.UI.WebControls.FontUnit).GetConstructor (
+                                       BindingFlags.Instance | BindingFlags.Public,
+                                       null,
+                                       new Type[] {cParamType},
+                                       null);
+                               if (c != null)
+                                       return new InstanceDescriptor (c, new object[] {cParam});
                        }
                        return null;
                }
@@ -1489,3 +1947,4 @@ namespace System.Web.Compilation
 }
 
 
+