Я столкнулся с этим вопросом, для более простого случая желания родового статического метода, который мог бы взять что-нибудь «обнуляемый» (либо ссылки на типы или Nullables), который привел меня этот вопрос без удовлетворительного решения. Поэтому я придумал свое решение, которое было относительно легче решить, чем заявленный вопрос OP, просто имея два перегруженных метода, один из которых принимает T
и имеет ограничение where T : class
, а другое - T?
и имеет where T : struct
.
Я тогда понял, что решение может быть применен к этой проблеме, чтобы создать решение, которое проверяемое во время компиляции, что делает конструктор частным (или защищенным) и с использованием статического фабричного метода:
//this class is to avoid having to supply generic type arguments
//to the static factory call (see CA1000)
public static class Foo
{
public static Foo<TFoo> Create<TFoo>(TFoo value)
where TFoo : class
{
return Foo<TFoo>.Create(value);
}
public static Foo<TFoo?> Create<TFoo>(TFoo? value)
where TFoo : struct
{
return Foo<TFoo?>.Create(value);
}
}
public class Foo<T>
{
private T item;
private Foo(T value)
{
item = value;
}
public bool IsNull()
{
return item == null;
}
internal static Foo<TFoo> Create<TFoo>(TFoo value)
where TFoo : class
{
return new Foo<TFoo>(value);
}
internal static Foo<TFoo?> Create<TFoo>(TFoo? value)
where TFoo : struct
{
return new Foo<TFoo?>(value);
}
}
Теперь мы можем использовать его как это:
var foo1 = new Foo<int>(1); //does not compile
var foo2 = Foo.Create(2); //does not compile
var foo3 = Foo.Create(""); //compiles
var foo4 = Foo.Create(new object()); //compiles
var foo5 = Foo.Create((int?)5); //compiles
Если вы хотите, конструктор без параметров, вы не получите Тонкость перегрузки, но вы можете сделать что-то вроде этого:
public static class Foo
{
public static Foo<TFoo> Create<TFoo>()
where TFoo : class
{
return Foo<TFoo>.Create<TFoo>();
}
public static Foo<TFoo?> CreateNullable<TFoo>()
where TFoo : struct
{
return Foo<TFoo?>.CreateNullable<TFoo>();
}
}
public class Foo<T>
{
private T item;
private Foo()
{
}
public bool IsNull()
{
return item == null;
}
internal static Foo<TFoo> Create<TFoo>()
where TFoo : class
{
return new Foo<TFoo>();
}
internal static Foo<TFoo?> CreateNullable<TFoo>()
where TFoo : struct
{
return new Foo<TFoo?>();
}
}
И использовать его как это:
var foo1 = new Foo<int>(); //does not compile
var foo2 = Foo.Create<int>(); //does not compile
var foo3 = Foo.Create<string>(); //compiles
var foo4 = Foo.Create<object>(); //compiles
var foo5 = Foo.CreateNullable<int>(); //compiles
Есть несколько недостатков для этого решения, является то, что вы можете предпочесть использовать «новый» для создания объектов. Другим является то, что вы не сможете использовать Foo<T>
в качестве аргумента общего типа для ограничения типа чего-то вроде: where TFoo: new()
. Наконец, это бит дополнительного кода, который вам нужен здесь, который бы увеличился, особенно если вам нужно несколько перегруженных конструкторов.
@Tim, который не допускает Nullables – Rik
Эта ссылка может помочь вам: http://social.msdn.microsoft.com/Forums/en-US/df6bd378-7ff9-4298-852d-a92deecc77e7/nullable-constraint –
Это невозможно сделать напрямую. Возможно, вы можете рассказать нам больше о вашем сценарии? Или, может быть, вы можете использовать 'IFoo' как рабочий тип и создавать экземпляры с помощью заводского метода? Это можно заставить работать. –
Jon