Литье делегата

Я новичок в С#, поэтому мой вопрос может быть простым, но здесь идет.

Я пытаюсь работать с делегатами и, похоже, с этой проблемой.

.....
    public delegate double delegateA();
    public delegate double delegateB();

    public static double myFunc()
    {
        return 0;
    }
    public static delegateA myTest()
    {
        return myFunc;
    }

    static void Main(string[] args)
    {
        delegateB myFuncDelegate;

        myFuncDelegate = myTest();  // <-- Error: Cannot implicitly convert type....
    }
.....

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

Надеюсь, ты поможешь мне.

Ответы

Ответ 1

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

 delegateB myFuncDelegate = new delegateB(myTest());

который будет работать. (Обратите внимание, что "совместимость" не обязательно означает, что подписи идентичны. Подробнее см. Спецификацию языка.)

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

// Two delegate types with the same signature
delegate void Foo();
delegate void Bar();

class Test
{
    static void Main()
    {
        // Actual value is irrelevant here
        Foo foo = null;

        // Error: can't convert like this
        // Bar bar = foo;

        // This works fine
        Bar bar = new Bar(foo);
    }
}

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

 Action<object> foo = x => Console.WriteLine(x.GetHashCode());
 Action<string> bar = foo;

... потому что Action<T> является контравариантным в T (поэтому он фактически объявлен как Action<in T>). Это ссылочное преобразование - он не создает нового делегата, как это делает первый образец. Однако это не доступно для просто "совместимых" делегатов - только общие.

Ответ 2

Кроме того, не совсем то, о чем вы просили, но интересно - это не работает:

Func<double> func_double = () => 1;
Func<object> func_object;

func_object = func_double;

Но это делает:

Func<string> func_string = () => "hello";
Func<object> func_object;

func_object = func_string;

Различие в примере строки - это использование ссылочных типов, которые могут быть переданы объекту, в то время как двойной должен быть помещен в бокс, тем самым блокируя прямой литой