Оператор вызова функции перегрузки в С#
Возможно ли перегрузить оператор функции по умолчанию (оператор() в С#? Если так - как? Если нет, есть ли способ обхода такого эффекта?
Спасибо,
Асаф
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:
Мотивация заключается в том, чтобы сделать класс, или экземпляр, как функцию, сделать удобный интерфейс ведения журнала. Кстати, в С++ это выполнимо и разумно.
Ответы
Ответ 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
}
}