2016-06-05 9 views
0

У меня есть отдельные реализации универсального интерфейса (один для классов, один для структур), и я хочу использовать статический метод Create, который обрабатывает конструкцию. Но я не могу понять, как заставить компилятор доверять мне правильное ограничение типа. Я полностью понимаю, почему он не работает, но как мне обойти это?Построение общих типов без ограничения класса/структуры

public interface ISomething<T> { } 

internal class SomethingForReferenceTypes<T> 
    : ISomething<T> where T : class { } 

internal class SomethingForValueTypes<T> 
    : ISomething<T> where T : struct { } 

public static class Something 
{ 
    public static ISomething<T> Create<T>() 
    { 
    bool TIsAReferenceType = IKnowHowToFigureThisOut(); 
    if (TIsAReferenceType) 
     return new SomethingForReferenceTypes<T>(); // ← T is not accepted here. 
    else 
     return new SomethingForValueTypes<T>(); // ← T is not accepted here. 
    } 
} 
+0

похоже, что вам нужно будет использовать отражение, чтобы создать общие типы, а затем активировать их. – Nkosi

ответ

3

Я не думаю, что вы собираетесь быть в состоянии сделать это непосредственно, но вы можете легко использовать отражение для создания экземпляра:

Type openType = TIsAReferenceType 
    ? typeof(SomethingForReferenceTypes<>) 
    : typeof(SomethingForValueTypes<>); 
Type constructedType = openType.MakeGenericType(typeof(T)); 
object ret = Activator.CreateInstance(constructedType); 
return (ISomething<T>) ret; 
+0

Не компилятор не пожаловался бы на использование 'T' с классами, подобными исходной ошибке? – Nkosi

+0

@Nkosi, да, это так. –

+0

@Nkosi: Оо, вполне возможно. Doh. Закрепим его. –

1

Короткий ответ, вы не можете , Вы можете сделать это с отражением, но для достижения максимальной эффективности вам необходимо выполнить динамическую отправку для статического метода Create:

public static class Something<T> 
{ 
    public static readonly Func<ISomething<T>> Create; 
    static Something() 
    { 
     var name = typeof(T).IsValueType ? "ValueType" : "Reference"; 
     var method = typeof(Something<T>).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static) 
             .MakeGenericMethod(typeof(T)); 
     Create = (Func<ISomething<T>>)Delegate.CreateDelegate(typeof(Func<ISomething<T>>), null, method); 
    } 

    static ISomething<T0> Reference<T0>() 
     where T0 : class 
    { 
     return new SomethingForReferenceTypes<T0>(); 
    } 
    static ISomething<T0> ValueType<T0>() 
     where T0 : struct 
    { 
     return new SomethingForValueTypes<T0>(); 
    } 
} 

Затем вы можете вызвать его с любым T, через Something<T>.Create(). Должно быть намного более эффективным, чем Activator.CreateInstance.

+0

Интересный подход со статичностью, это может действительно ускорить повторные вызовы. –

Смежные вопросы