I have written an extension method in csharp for an MVCContrib Html helper and was surprised at the form of the generic constraint, which on the face of it seems to circularly reference itself through the type parameter.
This being said the method compiles and works as desired.
I would love to have someone explain why this works and if a more intuitive intuitive syntax exists and if not if anyone know why?
Here is the compiling and function code but I have removed the List of T example as it clouded the issue. as well as an analogous method using a List<T>.
namespace MvcContrib.FluentHtml
{
public static class FluentHtmlElementExtensions
{
public static TextInput<T> ReadOnly<T>(this TextInput<T> element, bool value)
where T: TextInput<T>
{
if (value)
element.Attr("readonly", "readonly");
else
((IElement)element).RemoveAttr("readonly");
return element;
}
}
}
/*analogous method for comparison*/
public static List<T> AddNullItem<T>(this List<T> list, bool value)
where T : List<T>
{
list.Add(null);
return list;
}
In the first method the constraint T : TextInput<T> seems to all intents and purposes, circular. However if I comment it out I get a compiler error:
"The type 'T' cannot be used as type parameter 'T' in the generic type or method 'MvcContrib.FluentHtml.Elements.TextInput<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'MvcContrib.FluentHtml.Elements.TextInput<T>'."
and in the List<T> case the error(s) are:
"The best overloaded method match for 'System.Collections.Generic.List.Add(T)' has some invalid arguments Argument 1: cannot convert from '<null>' to 'T'"
I could imagine a more intuitive definition would be one that includes 2 types, a reference to the Generic Type and a reference to the Constraining Type eg:
public static TextInput<T> ReadOnly<T,U>(this TextInput<T> element, bool value)
where U: TextInput<T>
or
public static U ReadOnly<T,U>(this U element, bool value)
where U: TextInput<T>
but neither of these compile.