Подтвердить что ты не робот

Оператор вызова функции перегрузки в С#

Возможно ли перегрузить оператор функции по умолчанию (оператор() в С#? Если так - как? Если нет, есть ли способ обхода такого эффекта?

Спасибо,
Асаф

EDIT:
Я пытаюсь дать классу оператор по умолчанию, что-то вроде строк:

class A {
    A(int myvalue) {/*save value*/}

    public static int operator() (A a) {return a.val;}
    ....
   }

...
A a = new A(5);
Console.Write(A());

ИЗМЕНИТЬ 2:
Я прочитал спецификацию, и я понимаю, что нет прямого способа сделать это. Я надеялся, что это обходное решение.

ИЗМЕНИТЬ 3: Мотивация заключается в том, чтобы сделать класс, или экземпляр, как функцию, сделать удобный интерфейс ведения журнала. Кстати, в С++ это выполнимо и разумно.

4b9b3361

Ответ 1

Нет, () не является оператором, поэтому он не может быть перегружен. (Это неверно, см. комментарий к Eric Lippert ниже). Скобки являются частью синтаксиса С#, которые используются для выражения набор аргументов, передаваемых методу. () просто указывает, что данный метод не указал формальных параметров и поэтому не требует аргументов.

Что вы пытаетесь сделать? Возможно, если вы представите небольшой пример проблемы, мы сможем помочь с решением.

Изменить: Хорошо, я понимаю, что вы сейчас делаете. Вы всегда можете создать делегат, который сопоставляется методу в экземпляре, подобном этому (при условии, что class A определяет метод, подобный этому: public void Foo() { }):

Action action = someA.Foo;

Затем вы можете вызвать делегата с помощью простого синтаксиса:

action();

К сожалению (или нет, в зависимости от ваших предпочтений), это почти так же близко, как и С#, позволит вам получить такой синтаксис.

Ответ 2

Нет. Раздел 7.2.2 спецификации С# определяет перегружаемые операторы как:

UNARY: + -! ~ ++ - true false
BINARY: + - */% и | < → ==! = > < >= < =

В любом случае, ваша читаемость пойдет на ад. Может быть, есть еще один способ добиться того, что вы пытаетесь сделать?

Ответ 3

Возможно ли перегрузить оператор функции по умолчанию (оператор() в С#? Если так - как?

В С# только методы и делегаты имеют смысл ссылаться как функции. В С# делегаты находятся так близко, как вы попадаете в объекты функций С++ Dynamic. Это потребует, чтобы вы вызывали именованные методы и не позволяли использовать короткий синтаксис, который вы пытаетесь реализовать. Но он был бы слабо связан и мог бы изящно потерпеть неудачу.

Использование более простых .Net-функций

Существуют и другие решения, которые вы могли бы изучить.

Интерфейсы:

Создайте базовый интерфейс ILoggable со стандартными методами.

Методы расширения:

Создайте свой интерфейс ведения журнала с помощью .Log() методов расширения. Методы расширения могут быть сделаны универсальными и могут принимать базовые типы, например object, поэтому вам не придется изменять существующие классы для поддержки этого.

Переопределить ToString:

Ведение журнала означает, что вы пытаетесь преобразовать свои данные в текст (чтобы он мог быть зарегистрирован). Имея это в виду, вы можете просто переопределить метод ToString.

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

Существующие решения

Существующие библиотеки протоколов .Net, которые я видел, полагаются на то, что вы переопределяете оператор ToString. Как я сказал выше, это имеет смысл, потому что ваш журнал является текстовым.

Для предыдущих работ в области регистрации .Net см. следующие библиотеки:

Примечание о встроенных типах делегатов

Убедитесь, что во всех этих случаях вы используете встроенные типы делегатов, а не определяете свои собственные типы делегатов. В конце он будет менее запутанным и потребует меньше писать код.

// function that returns void
Action a1 = ...;
Action<TParameter1> a2 = ...;
Action<TParameter1, TParameter2> a3 = ...;
// etc

// function that returns a value
Func<TReturn> f1 = ...;
Func<TParameter1, TReturn> f2 = ...;
Func<TParameter1, TParameter2, TReturn> f3 = ...;
// etc

Ответ 4

Да, это можно сделать абсолютно с помощью типа dynamic (более подробная информация найдена здесь).

using System.Dynamic.DynamicObject

class A : DynamicObject 
{
    private int val;

    A(int myvalue)
    {
        this.val = val;
    }

    public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) {
        result = this.val;
        return true;
    }
}

...

dynamic a = new A(5);
Console.Write(a());

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

Я предположил, что вы хотели использовать a, а не a в строке Console.Write.

Ответ 5

Почему вы хотите это сделать? Возможно, вы ищете перегрузку оператора [] ?

Ответ 6

Вы не можете перегрузить (), но вы можете взять объект и сделать делегат (похожий на указатель функции) одним из своих методов:

class Foo
{ 
    private Bar bar;
    // etc.

    public Baz DoSomething(int n)
    {
        // do something, for instance, 
        // get a Baz somehow from the 'bar' field and your int 'n'
        // ...
    }
}

Теперь DoSomething - это метод, который принимает int и возвращает Baz, который совместим с типом делегата Func<int, Baz>.
(Там Action и Action<T> для методов, которые возвращают void, и принимают, соответственно, ни один или один аргумент. Также Func<T1, T2, TResult> и варианты для принятия большего количества аргументов.)

Итак, у вас может быть метод, который принимает Func<int, Baz> и делает с ним все:

void Frob(Func<int, Baz> f)
{
        Baz b = f(5); 
        // do whatever with your baz
}

Наконец, создание делегата и передача его в Frob происходит следующим образом:

Foo foo = new Foo();
Func<int, Baz> f = new Func<int, Baz>(foo.DoSomething);
Frob(f);

Помогает ли это вообще? Я все еще не совсем понимаю, что именно вы хотите выполнить.

Ответ 7

Вы упомянули, что хотите выполнить регистрацию, вот как это сделать с делегатами:

FooBar MyAlgorithm(Foo paramA, Bar paramB, Actions<string> logger) {
    logger("Starting algorithm.")
    FooBar result = ...;
    logger("Finished algorithm.");
    return result;
}

Когда вы запустите это, вы можете войти в консоль:

MyAlgorithm(a, b, (text) => Console.WriteLine(text));

Или зарегистрируйтесь в текстовом поле Windows Forms:

TextBox logbox = form.GetLogTextBox();
MyAlgorithm(a, b, (text) => logbox.Text += text + Environment.NewLine);

Ответ 8

Отметьте неявное преобразование. Другим вариантом будет explict conversion, но тогда вам нужно будет указать тип объекта.

public class A
{
    public A(int myValue)
    {
        this.MyValue = myValue;
    }
    public int MyValue { get; private set; }

    public static implicit operator int(A a)
    {
        return a.MyValue;
    }
    public static implicit operator A(int value)
    {
        return new A(value);
    }
    // you would need to override .ToString() for Console.WriteLine to notice.
    public override string ToString()
    {
        return this.MyValue.ToString();
    }
}
class Program
{
    static void Main(string[] args)
    {
        A t = 5;
        int r = t;
        Console.WriteLine(t); // 5
    }
}