Вот практический пример того, как вы хотели бы иметь дополнительный параметр типа конструктора, и обходной путь.
Я собираюсь представить простую оболочку RefCounted
для IDisposable
:
public class RefCounted<T> where T : IDisposable
{
public RefCounted(T value)
{
innerValue = value;
refCount = 1;
}
public void AddRef()
{
Interlocked.Increment(ref refCount);
}
public void Dispose()
{
if(InterlockedDecrement(ref refCount)<=0)
innerValue.Dispose();
}
private int refCount;
private readonly innerValue;
}
Кажется, все в порядке.Но рано или поздно вы захотите привести RefCounted<Control>
к RefCounted<Button>
, в то же время сохраняя подсчет ссылок на оба объекта, т. Е. Только когда оба экземпляра располагаются для удаления базового объекта.
Лучший способ - если вы могли бынаписать (как это умеют делать люди на C ++)
public RefCounted(RefCounted<U> other)
{
...whatever...
}
Но C # этого не позволяет.Поэтому решение заключается в использовании некоторой косвенности.
private readonly Func<T> valueProvider;
private readonly Action disposer;
private RefCounted(Func<T> value_provider, Action disposer)
{
this.valueProvider = value_provider;
this.disposer = disposer;
}
public RefCounted(T value) : this(() => value, value.Dispose)
{
}
public RefCounted<U> Cast<U>() where U : T
{
AddRef();
return new RefCounted<U>(() => (U)(valueProvider()),this.Dispose);
}
public void Dispose(){
if(InterlockedDecrement(ref refCount)<=0)
disposer();
}
Если в вашем классе есть какие-либо поля универсального типа, у вас нет выбора, кроме как поместить все эти типы в класс.Однако, если вы просто хотите скрыть какой-то тип от конструктора, вам нужно будет использовать описанный выше трюк - иметь скрытый конструктор, чтобы собрать все воедино, и определить обычную универсальную функцию для вызова этого конструктора.