Приведение параметра типа к базовому типу без упаковки

Есть ли способ сделать код вроде этой работы:

public class Func2<A, B>
{
    private Func<A, B> f;

    public Func2(Func<A, B> f)
    {
        this.f = f;
    }

    public object invoke(object obj, long l)
    {
        if (typeof(B) == typeof(long))
        {
            if (obj != null)
                l = (long)obj;
            return f((B)l); //error! cannot convert type 'long' to 'B'
        } else {
            return f((B)obj);
        }
    }
}

Проблема здесь в том, что я не могу напрямую привести B к long без приведения B к объекту первым. Я стараюсь любой ценой избавиться от необходимости упаковывать данные, так как это значительно замедлит быстрые операции с функциями. Так есть ли способ добиться этого?

Я знаю, что мог бы на самом деле определить специализированный Func2, чтобы конкретно обрабатывать случай, когда B длинная. Но по мере роста арности функции комбинация длинных и объектов растет экспоненциально - и в реальном случае использования я хочу также поддерживать двойные значения! Есть ли способ поддержать это без бокса? Может быть, с небезопасным кодом?

Спасибо! Cauê

2 ответа

Решение

Вы можете перегрузить метод, и вместо long значение для AВы можете привести делегата к Func<long, B>:

public class Func2<A, B> {

  private Func<A, B> f;

  public Func2(Func<A, B> f) {
    this.f = f;
  }

  public B invoke(long a) {
    if (typeof(A) == typeof(long)) {
      return (f as Func<long, B>)(a);
    } else {
      throw new NotSupportedException();
    }
  }

  public B invoke(object a) {
    return f((A)a);
  }

}

Пример:

Func2<long, string> f = new Func2<long, string>(l => l.ToString());

Console.WriteLine(f.invoke(42)); // calls the invoke(long) method
Console.WriteLine(f.invoke("x")); // calls the invoke(object) method

Только что узнал ответ!:)

public object invoke(object obj, long l)
{
    if (typeof(B) == typeof(long))
    {
        if (obj != null)
            l = (long)obj;
        Func<A, long> x = (Func<A, long>)(object)f;
        return x(l);
    } else {
        return f((B)obj);
    }
}

Таким образом, нам не нужно автоматически вставлять long в объект, но мы фактически приводим тип Func для получения указанного нами long!

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

К настоящему времени у нас есть следующий haXe-код:

var f:Int->Int->Float = function(x:Int, y:Int) return x + y + 0.5;
var f2:Dynamic->Dynamic->Dynamic = f; // ok
var f3:Dynamic->Int->Dynamic = f; //also ok
f2(10, 30); // ok - this will box the 10 and 30

То, что я пытаюсь сделать, - это создать тип Fun3, который имеет вызов invoke, который будет принимать как коробочные, так и незаписанные аргументы. Если базовая функция действительно принимает распакованные типы, она сначала попытается использовать их.

Спасибо!!

Другие вопросы по тегам