2014-02-09 7 views
11

Я очень смущен этим, поэтому, если у кого-то есть идеи. У меня есть универсальный методДобавление общих ограничений во время выполнения?

public void Foo<TClass>(TClass item) where TClass : class 
{ } 

И я хочу, чтобы вызвать этот метод из другого универсального метода, но этот шаблонный метод не имеет ограничения типа «где TClass: класс»

public void Bar<T>(T item) 
{ 
    this.Foo<T>(item); 
} 

Это Безразлично «т работу, я получаю ошибку

„тип „Т“ должен быть ссылочный тип, чтобы использовать его в качестве параметра "TClass“

Который я понимаю. Но мой вопрос заключается в следующем: есть ли что-нибудь, что я могу сделать с синтаксисом C#, чтобы «фильтровать» общий тип «T», чтобы передать его в «this.Bar», если это класс. Что-то вроде ....

public void Bar<T>(T item) 
{ 
    if (typeof(T).IsClass) 
     this.Foo<T **as class**>(); 
} 

Я понимаю, что могу использовать отражение, чтобы вызвать Foo, но это просто похоже на обман. Есть ли что-то, что я могу сделать с C# для передачи «T» с ограничением во время выполнения?

Кроме того - я не могу изменить ограничение на методе «Bar», как это происходит от интерфейса, так что ограничение должно соответствовать ограничению на интерфейсе

+0

Возможно, вы имели в виду «this.Foo ();" ? – Euphoric

+0

хорошо пятнистый - отредактирован :) – jcharlesworthuk

+1

Так почему бы вам не использовать 'if (typeof (T) .IsClass)' ?? –

ответ

4

Единственный способ вызова Foo без отражения, является приведение item к одному из типов/классов в его иерархии (после правильной проверки IsClass).

Очевидно, что в вашей иерархии есть только один тип, который вы знаете a priori: Object.

public void Bar<T>(T item) 
{ 
    if (typeof(T).IsClass) 
     this.Foo((object) item); 
} 

Edit:

Кроме того, в одном из комментариев вы сказали, что вы добавили class ограничение быть инстанцировать T. Вам это не нужно, вам нужен new constraint.

+0

Ничего себе, что на самом деле компилируется, я полностью забыл, что вы можете «раскрасить» дженерики, подобные этим ура! Также, да, вы правы, я действительно сделал новое ограничение, но оставил его из этого вопроса, чтобы упростить его :) – jcharlesworthuk

-1

Я считаю, что нет никакого способа, чтобы сделать его компиляцию , Для совершения звонка вам придется использовать отражение.

Собственно. Вы можете обмануть, если содержать его в классе:

public class Container<T> 
    { 
     public Container(T value) 
     { 
      Value = value; 
     } 

     public T Value { get; private set; } 
    } 

    public void Bar<T>(T item) 
    { 
     this.Foo<Container<T>>(new Container<T>(item)); 
    } 

, но это добавляет один слой, необходимо вызвать сквозной и делает типы менее ясно.

+0

Это не сработает, потому что 'Container ' не соответствует 'Foo (T item)', и если вы его поменяете на: 'Foo (Container item)', чем он все равно скажет, что ' T' должен быть тип ref. –

+0

@ Some1Pr0 Что? – Euphoric

+0

он говорит, что строка 'new Container (item)' не будет компилироваться из-за ограничения типа – jcharlesworthuk

4

К сожалению, нет способа сделать это, не изменяя Bar, чтобы иметь общее ограничение class или с использованием отражения. Для компиляции C# должен знать во время компиляции, что T действительно является значением class. Нет возможности использовать динамический тест, например typeof(T).IsClass, чтобы удовлетворить это ограничение времени компиляции.

Вы упомянули в вопросе, что вы не можете изменить Bar, но похоже, что вы готовы принять возможность динамического сбоя. Может быть, вместо того, чтобы изменить Foo не имеют ограничений, но вместо того, чтобы бросить исключение, когда T не тип класса

+0

Привет, спасибо за ответ. Я установил ограничение на «Foo», потому что я хотел использовать «Foo» для создания экземпляра нового экземпляра элемента. Поэтому «Foo» на самом деле действительно нужно взять объект, который может быть создан при помощи «нового T()». Я предпочел бы исключение времени выполнения в «Бар», чем «Foo». Но если отражение - единственный вариант, то я думаю, это прекрасно :) – jcharlesworthuk

0
if (typeof(T).IsClass) 
{ 
    this.GetType() 
     .GetMethod("Foo", System.Reflection.BindingFlags.Instance | 
          System.Reflection.BindingFlags.Public) 
     .Invoke(this, new object[] { item }); 
} 
+0

Я уверен, что он явно спрашивает, есть ли альтернатива отражению. – Euphoric

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