Overloading function call operator in C#

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

In C#, only methods and delegates make sense to invoke as functions. In C#, delegates are as close as you get to the C++ function objects you are asking about.

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

You can’t get exactly what you want, but you can get vaguely close (syntax-wise).

Using overloaded conversion operators

Definition:

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

Usage:

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

This gets the final syntax you want, but requires you to do an intermediate conversion where you specify the type.

You can do this by:

  • Assigning your value to a local variable, or passing it to a function taking a matching delegate type (implicit conversion)
  • Casting it (explicit conversion)

Using indexers

Definition:

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

Usage:

variable[value1]();

The indexer version has funny-looking syntax, but so does the example in your original question (wrt the standard C# idioms). It is also limited, because you can’t define an indexer that takes zero parameters.

A work-around if you want a no-parameter function is to make a dummy parameter (probably of type object) and passing a throw-away value to it (probably null). But that solution is really gross, and requires you to look under the hood to understand the usage. It would also break if you ever wanted an overload that took a single parameter of your dummy type.

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

With this motivation in mind, I might suggest you abandon those options above. They are overkill for this problem. If you broaden your allowed solutions, you may find you like one of them better.

Using dynamic instead

The other methods I mentioned require strong typing, and are in no way generic. This may be a huge disadvantage for what you are describing.

If you want weaker binding, you could look into Dynamic. This would require you to invoke named methods, and wouldn’t allow the short syntax you’re trying to implement. But it would be loosely bound, and could fail gracefully.

Using simpler .Net features instead

There are other solutions you could look into.

Interfaces:

Create a base ILoggable interface, with standardized methods.

Extension methods:

Create your logging interface with .Log() extension methods. Extension methods can be made generic, and can take base types, like object, so you wouldn’t have to modify your existing classes to support this.

Override ToString:

Logging implies that you are trying to convert your data into text (so it can be logged). With this in mind, you could simply override the ToString method.

You can create method overloads in all these cases, but they will be strongly bound to each type. The solution you requested in your original question also is strongly bound to the type, though, so these solutions aren’t really at a disadvantage.

Existing solutions

The existing .Net logging libraries I’ve seen rely on you overriding the ToString operator. As I said above, this makes sense, because your log is textual.

For previous art on .Net logging, see these libraries:

  • http://logging.apache.org/log4net/
  • http://nlog-project.org/
  • http://docs.castleproject.org/Windsor.Logging-Facility.ashx (a generic logger)

Note about built-in delegate types

Make sure you use the built-in delegate types in all these cases, instead of defining your own delegate types. It will be less confusing in the end, and require you to write less code.

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

Leave a Comment

tech