2

我想创建一个通用方法:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)

我的代码中有很多变量,它们是List<T>, IEnumerable<T>, xxxCollection, T[], 等等……这个方法也有一个重载,它将采用不可枚举的值。string是否可以在类型参数约束中禁止特定类(如)?

我已经创建了一个这样的重载:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, object value)

这种重载有利于处理单个值,但处理值的集合需要稍微不同的实现。但是,string实现IEnumerable所以我的所有字符串变量都将被发送到错误的重载,除非我可以告诉编译器它们应该被排除。

4

4 回答 4

3

不可以。泛型类型参数约束只能强制执行约束而不是约束。

运行时类型检查可能是要走的路:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
{
    if (typeof(T) == typeof(string))
    {
        throw new IllegalOperationException(...);
    }
}

如果您想要传递给您的方法的所有类型都继承自同一个基类,或者实现相同的接口,您可以使用jrummell的单个约束建议来强制继承。

尽管它更不优雅,但如果您想支持异构类型,另一种方法是提供足够的重载来处理您的特定用例:

// 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)

在上面的示例中,您将无法调用MyMethod<string>,因为它不满足任何提供的类型约束。请注意,您不能为此使用类型约束,因为它们不是方法签名的一部分。

于 2013-03-25T17:55:27.450 回答
2

假设您只想将此扩展用于 Model 类型,您可以创建一个 Model 基类并限制T为实现它的类型。

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
    where T : ModelBase
于 2013-03-25T17:54:57.607 回答
2

考虑到您处理string.

鉴于您现有的接受 type 的方法, typeobject的参数string将导致您提出的新重载,因为IEnumerable<char>它比object. 但是,您不必放弃重载的想法,也不必求助于运行时检查。只需为string. 通过使编译器更容易使用场景来object回避整个决策。IEnumerable<T>

给定

void Foo(object argument)
{
    Console.WriteLine("object");
}

void Foo<T>(IEnumerable<T> argument)
{
    Console.WriteLine("enumerable T");
}

void Foo(string argument)
{
    Console.WriteLine("string");
}

方法调用列表

Foo("hello");
Foo(1);
Foo(new int[] { 1 });

产生输出

string
object
enumerable T

然后,您可以在一个地方进一步将您的字符串强制转换为您的对象重载。

void Foo(string argument)
{
    // Console.WriteLine("string");
    Foo((object)argument);
}
于 2013-03-25T18:25:13.183 回答
1

抱歉不行。

您只能指定以下类型的约束:

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

参考:类型参数的约束

现在,您可以使用其中的一些来限制,但不能锁定类型,只能指定您允许的类型,例如接口实现约束。

您可以使用接口或基类约束来具体说“我允许的类型必须都具有以下特征”。我会说这将是你最好的选择。

你确定泛型是正确的工具吗?

于 2013-03-25T17:56:02.097 回答