Открыть делегат завершается неудачно при попытке получить доступ к свойству Int или DateTime - PullRequest
1 голос
/ 03 марта 2012

Я тестировал, используя делегаты вместо отражения для какой-либо сортировки объектов, и это работало хорошо для строковых свойств, но если я пробую Int (или DateTime), он завершится неудачно и выдает

Ошибка привязки к целевому методу.

class Program
{
    static void Main(string[] args)
    {
        var sample = new SampleClass() { Num = 13, Text = "Sample" };

        Console.WriteLine(ReadProp(sample,"Text")); //Works
        Console.WriteLine(ReadProp(sample, "classProp")); //Works
        Console.WriteLine(ReadProp(sample, "Num")); //Throws 'Error binding to target method.'
    }

    //Use a Delegate to improve speed of accessing property instead of reflection
    static object ReadProp(SampleClass obj, string propName)
    {
        var method = obj.GetType().GetProperty(propName).GetGetMethod();
        var getForProp = (Func<SampleClass, object>)Delegate.CreateDelegate(typeof(Func<SampleClass, object>), null, method);
        return getForProp(obj);
    }
}

//A sample class for illustration purposes
class SampleClass
{
    public string Text { get; set; }
    public int Num { get; set; }
    public SampleClass classProp { get; set; }
}

Мой вопрос: Почему это работает для строк или других классов, но не для Int или DateTime?

Я вижу, что если я изменю свой Func<SampleClass, object> на Func<SampleClass, int>, он будет работать для моего Int, но я ожидал, что объект будет работать для обоих.

1 Ответ

2 голосов
/ 03 марта 2012

Почему это работает для строк или других классов, но не для Int или DateTime?

Поскольку метод, который возвращает int , не является методом, который возвращает ссылку object. Должно быть преобразование в бокс - поэтому что-то должно быть сделано, и Delegate.CreateDelegate пытается предоставить делегат, который просто вызывает делегат и возвращает результат, без преобразования значения.

Это немного больно, но, в принципе, я подозреваю, что вам следует либо создать Func с соответствующим возвращаемым значением и, используя это или , вы должны пройти через оболочку. делегат, который вызывает «реальный» делегат и упаковывает результат.

(Обратите внимание, что в вашем примере кода вы создаете делегата каждый раз, что будет не быстрее, чем отражение. Надеюсь, ваш реальный код более разумен:)

Если вы посмотрите на этот код из protobuf-csharp-port, вы увидите, что у меня есть метод, который делает именно это - лямбда-выражение вызывает строго типизированный делегат, а затем использует неявное преобразование на object (бокс при необходимости), чтобы указать значение. Вы должны быть в состоянии использовать что-то очень похожее. Однако, если вы сортируете, вы действительно хотите a Func<T, object>? Если вместо этого вы используете строго типизированный делегат, вы можете избежать всего этого бокса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...