Reputation: 13
I have an overloaded radio button extension method that is throwing the runtime execution off. The arguments of the first method can, in certain cases, be confused for the arguments of the second, and vice-versa.
public static MvcHtmlString MyRadioButton<TModel>( this HtmlHelper<TModel> helper, string property_name, string value, bool is_checked, string label = "", object attributes = null, bool separate_label = false, bool within_div = true, bool label_after = true )
{
// method implementation
}
and the overload:
public static MvcHtmlString MyRadioButton<TModel>( this HtmlHelper<TModel> helper, string property_name, string value, bool is_checked, object attributes = null, bool separate_label = false, bool within_div = true, bool label_after = true )
{
return MyRadioButton(helper, property_name, value, is_checked, "", attributes, separate_label, within_div, label_after);
}
In this case:
Html.MyRadioButton("name", "value", true, "");
the empty string is valid as both the object-type "attributes" argument and as the string-type "label" argument, causing a conflict between the methods.
Is there a way to generically type an argument and then exclude types from that definition in the method? I'm thinking maybe an inheritance class of the object type that accepts a list of types to exclude, like object<string>
. The alternative solution is to jumble the arguments of the overload so it is apparent which needs to be called, but that's far less elegant than properly typing the arguments.
Upvotes: 0
Views: 536
Reputation: 7226
If the attributes
parameter is meant to be used for POCOs and not value types (e.g. never string, integer, boolean, etc.), you could do something like this:
public static MvcHtmlString MyRadioButton<TModel, T>(
this this HtmlHelper<TModel>, ...,
T attributes,
... // omitted for brevity
) where T: new() // <- IMPORTANT LINE
{
// etc...
}
// which can be used with any anonymous or structured object:
helper.MyRadioButton(new { attribute1 = "hello world" });
helper.MyRadioButton(new MyClass());
// but not value types:
helper.MyRadioButton("this won't work for the above overload");
I would hope adding a generic constraint would be enough for the runtime to "know better" if this matches your use-case.
If you are only using this for POCOs, I would add the constraint either way. Then you never have to worry about accidentally passing in a value type.
Is there a way to generically type an argument and then exclude types from that definition in the constructor?
I dodged this question in my original answer. Using the where
constraint, you can restrict passed types to a type, but you cannot specify types to exclude. See Type parameter constraints language specification and documentation for more details.
Upvotes: 0
Reputation: 11760
Since the empty string could be either a string
or an object
you can distinguish whether you want the empty string to be passed as the label
or the attributes
when you call by specifying the name:
Html.MyRadioButton("name", "value", true, label: "")
Html.MyRadioButton("name", "value", true, attributes: "")
Upvotes: 1
Reputation: 5986
Maybe a simple solution like creating a special class of string can do the job better than using generic type constraint
[UPDATED]
Here is my suggestion:
public class MySpecialString
{
public string MyStringl;
public MySpecialString(string txt)
{
this.MyStringl = txt;
}
}
public class MyAttributes
{
public MyAttributes()
{
}
}
public static class Extentions
{
public static MvcHtmlString MyRadioButton<TModel>(this HtmlHelper<TModel> helper, string property_name,
string value, bool is_checked, MySpecialString mystring = null , object attributes = null, bool separate_label = false,
bool within_div = true, bool label_after = true)
{
// method implementation
}
public static MvcHtmlString MyRadioButton<TModel>(this HtmlHelper<TModel> helper, string property_name,
string value, bool is_checked, MyAttributes attributes = null, bool separate_label = false,
bool within_div = true, bool label_after = true)
{
// method implementation
}
}
Upvotes: 0
Reputation: 32770
Why the overload at all? Simply delegate inside one single method to the appropiate implementation defining a default value for label
that allows you to discern what option the consumer wants.
public static MvcHtmlString MyRadioButton<TModel>(this HtmlHelper<TModel> helper,
string property_name,
string value,
bool is_checked,
string label = null, //general case
object attributes = null,
bool separate_label = false,
bool within_div = true,
bool label_after = true )
{
if (label == null)
return myImplentationWithLabelNotDefined( //all arguments//);
return myImplementationWithLabelDefined(//all arguments//);
}
You can even define the helper methods as inner functions to avoid argument clutter...
Upvotes: 0