c# - 在 C# 中重载函数调用运算符

标签 c# operator-overloading

是否可以重载 C# 中的默认函数运算符(() 运算符)?如果是这样 - 怎么样?如果没有,是否有解决方法来产生类似的影响?

编辑:
我正在尝试为类提供默认运算符,类似于:

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: 动机是使一个类或一个实例表现得像一个函数,以创建一个方便的日志记录接口(interface)。顺便说一下,这在 C++ 中是可行且合理的。

最佳答案

Is it possible to overload the default function operator (the () operator) in C#? If so - how?

在 C# 中,只有方法和委托(delegate)才有意义作为函数调用。在 C# 中,委托(delegate)与 C++ 一样接近 function objects你问的是什么。

If not, is there a workaround to create a similar affect?

你无法准确地得到你想要的,但你可以模糊地接近(语法方面)。

使用重载的转换运算符

定义:

public static implicit operator DelegateType(TypeToConvert value)
{
    return value.TheMethodToCall;
}

用法:

var someValue = new TypeToConvert();
DelegateType someValueFunc = someValue;
someValueFunc(value1);

这会获得您想要的最终语法,但需要您在指定类型的地方进行中间转换。

您可以通过以下方式做到这一点:

  • 将您的值分配给局部变量,或将其传递给采用匹配委托(delegate)类型的函数(隐式转换)
  • 转换它(显式转换)

使用索引器

定义:

public DelegateType this[ParameterType1 value1, ...]
{
    get
    {
        // DelegateType would take no parameters, but might return a value
        return () => TheMethodToCall(value1);
    }
}

用法:

variable[value1]();

索引器版本的语法看起来很滑稽,但原始问题中的示例也是如此(标准 C# 习语)。它也有局限性,因为您不能定义采用零参数的索引器。

如果你想要一个无参数函数,一个解决方法是创建一个虚拟参数(可能是 object 类型)并向它传递一个一次性值(可能是 null)。但是这个解决方案真的很糟糕,需要你深入了解它的用法。如果您想要一个采用您的虚拟类型的单个参数的重载,它也会中断。

The motivation is to make a class, or an instance behave like a function, to make a convenient logging interface

考虑到这种动机,我可能会建议您放弃上述选项。他们对这个问题太过分了。如果您扩大允许的解决方案,您可能会发现您更喜欢其中的一种。

改用动态

我提到的其他方法需要强类型,并且绝不是通用的。对于您所描述的内容,这可能是一个巨大的劣势。

如果你想要更弱的绑定(bind),你可以查看 Dynamic .这将要求您调用命名方法,并且不允许您尝试实现的短语法。但它会松散地绑定(bind),并且可能会优雅地失败。

改用更简单的 .Net 功能

您还可以研究其他解决方案。

接口(interface):

使用标准化方法创建基本 ILoggable 接口(interface)。

扩展方法:

使用 .Log() 创建日志接口(interface) extension methods .扩展方法可以是通用的,并且可以采用基本类型,例如 object,因此您不必修改现有的类来支持这一点。

覆盖 ToString:

记录意味着您正在尝试将数据转换为文本(以便记录)。考虑到这一点,您可以简单地覆盖 ToString 方法。

您可以在所有这些情况下创建方法重载,但它们将与每种类型强绑定(bind)。不过,您在原始问题中请求的解决方案也与类型密切相关,因此这些解决方案并没有真正处于劣势。

现有解决方案

我见过的现有 .Net 日志记录库依赖于您覆盖 ToString 运算符。正如我上面所说,这是有道理的,因为您的日志是文本的。

有关 .Net 日志记录的先前技术,请参阅这些库:

关于内置委托(delegate)类型的注意事项

确保使用 built-in delegate types在所有这些情况下,而不是定义您自己的委托(delegate)类型。最终会减少混淆,并要求您编写更少的代码。

// 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

关于c# - 在 C# 中重载函数调用运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2450153/

相关文章:

c# - 如何以编程方式将 UWP 应用程序窗口置于最前面并在窗口最小化时将其最大化

c# - 流畅的 nHibernate 配置

c++ - 无法初始化友元函数运算符<<

C++函数重载不明确

使用变量类型的 C# 转换/拆箱

java - 启动一个进程会启动另一个进程,该进程会启动 Java 进程吗?

c# - 从时间 C# 中删除秒部分

c++ - 二元运算符+重载的返回值是否应该是 const 并且它会干扰优化吗?

c++ - 不同类中的前置和后置增量运算符

c# - 为什么我不能在 C# 中重载 += 运算符?但我还能用吗?