I'd like to create a generic method:
MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
I have many variables in my code which are List<T>
, IEnumerable<T>
, xxxCollection
, T[]
, etc... This method also has an overload which will take non enumerable values. Is it possible to prohibit specific classes (such as string
) in the type parameter constraints?
I've already created one overload like this:
MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, object value)
This overload is good for dealing with individual values, but dealing with collections of values requires a slightly different implementation. However, string
implements IEnumerable
so all my string variables will be sent to the wrong overload unless I can tell the compiler that they should be excluded.
No. Generic type parameters constraints can only enforce positive constraints not negative constraints.
Run-time type checking is probably the way to go:
MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
{
if (typeof(T) == typeof(string))
{
throw new IllegalOperationException(...);
}
}
If all the types you want to pass to your method inherit from the same base class, or implement the same interface, you can use jrummell's suggestion of a single constraint to enforce inheritance.
Although it's much more inelegant, another way of doing this if you want to support heterogeneous types would be providing enough overloads to handle your particular use cases:
// supports int, float, DateTime, etc.
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<int> value)
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<float> value)
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<DateTime> value)
// supports implementations of MyInterface
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<IMyInterface> value)
In the above example you would not be able to call MyMethod<string>
since it doesn't satisfy any of the provided type constraints. Note that you can't use type constraints for this though as they are not part of the method signature.
Unfortunately, no.
You can only specify the following types of constraints:
where T : struct // T must be a value type
where T : class // T must be a reference type
where T : new() // T must have a parameterless constructor
where T : <base class name> // T must inherit from <base class>
where T : <interface name> // T must implement <interface>
where T : U // T must inherit from U, where U is another
// generic parameter
Reference: Constraints on Type Parameters.
Now, you can use some of these to restrict, but not to lock types out, only to specify the types you allow, such as the interface implementation constraint.
You can use the interface or base class constraint to specifically say "the types I allow must all have the following characteristic". I would say this would be your best option.
Are you sure generics is the right tool here?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With