Добавление общих ограничений во время выполнения?

Я очень смущен этим, поэтому, если у кого-то есть идеи. У меня есть общий метод

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

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

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

Это не работает, я получаю сообщение об ошибке

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

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

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

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

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

Ответ 1

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

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

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

Изменить:

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

    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));
    } 

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