1

-REWORD-
I have a method with a few overloads that share its type, all meant as a way of enabling optional parameters / ways of representing them.
if i write them as

T doStuff(int a) => doStuff(a.ToString());
T doStuff(string b) => doStuff(null, b);
T doStuff(string? a, string b)
{
    T ret=realComputation();
    return ret;
}

I can change the 'T' part to anything (MyClass, MyClass2, string) and only edit the last overload.
I can also change T to void, as Lamdas allow for f() => voidTypedMethod().

void doStuff(int a) => doStuff(a.ToString());
void doStuff(string b) => doStuff(null, b);
void doStuff(string? a, string b)
{
    realComputation();
    return;
}

Now,
in the step between two overloads i need to convert their parameters, and therefore cannot use Lambdas (without horrible workarounds that would defeat the point of editing less parts).

 T doStuff(int a) {
    //cast to next overload doing some computations
    string computedString = a.ToString();
    return doStuff(computedString);
}
T doStuff(string b) => doStuff(null, b);
T doStuff(string? a, string b)
{
    T ret = realComputation();
    return ret;
}

if i was now to change the type to void the compiler would raise an error, as void methods cannot use return except for "return;"

I was wondering if there was some syntax that allowed me to leave the return voidReturningMethod() there, enabling the same quick-editing lamda's syntax allow for.
As void methods do not return null (return; <!=> return null) the compiler would have to translate "return voidRetMethod();" to "voidRetMethod(); return;"

the code that prompted the question:

    public void AppendMessage(string styleKey, string text)
        => AppendMessage(styleKey, null, text);
    public void AppendMessage(string styleKey, string? title, string body) {
        Debug.Assert(MessageFormatsMap.ContainsKey(styleKey));
        /*return*/ AppendMessage(MessageFormatsMap[styleKey], title, body);
        
    }
    public void AppendMessage(MessageFormat mf, string? title, string body)
    {
        box.AppendText($"{(title is null ? "" : $"[{title}]")}\n{body}", mf.ForeColor);
    }

I'll probably have this methods return their class instance in the future, to allow for chained calls. Which leads me to the "how can i add/edit the least amount of code in the future?"

I also see it as a way of stating that they're bound to return the same Type and result.

-ORIGINAL QUESTION-

I'm new to C# and i was wondering if there is some elegant way to code this behaviour:
I have a method with a few overloads that share its type, all meant as a way of enabling optional parameters / ways of representing them.

    public void AppendMessage(string styleKey, string text) => AppendMessage(styleKey, null, text);
    public void AppendMessage(string styleKey, string? title, string body) {
        Debug.Assert(MessageFormatsMap.ContainsKey(styleKey));
        return AppendMessage(MessageFormatsMap[styleKey], title, body); ;
    }
    public void AppendMessage(MessageFormat mf, string? title, string body)
    {
        box.AppendText($"{(title is null ? "" : $"[{title}]")}\n{body}", mf.ForeColor);
    }

At the moment the type is void, but that could change.
For this reason i'd like for each overload to return the method of its next overload, which i'm sure they'll keep sharing, so that i won't be forced to add the return statements later on, upon adding non-void type.

The first 'AppendMessage' definition doesn't raise any error, whilst the second (of course) does:

"CS0127: ~ AppendMessage has type void, a return keyword cannot be followed by an 'object expression'"

I browsed the web and the forum for an appropriate Attribute (as i cannot always use Lambda functions) but i didn't manage to find one.

Is there one? or some other way to accomplish this?
It would also be nice if i could explicitate the constraint that the three methods must share the same type.

  • What are you planing to get as a result? do you have any sample data? The problem is your `return` in your second method, i am not quite sure what are you trying to do – DonMiguelSanchez Jun 23 '23 at 10:30
  • `return` implies a "result". However your method simply have no result at all. You can however just *call* a method without that keyword. – MakePeaceGreatAgain Jun 23 '23 at 10:32
  • 1
    `void` means that no value is returned, meaning that you cannot `return` a value from the function's body. When you change the return type from `void` to something else, such as `object`, the compiler will let you know that you _must_ add a `return` statement. – knittl Jun 23 '23 at 10:33
  • 1
    Likely a duplicate: https://stackoverflow.com/questions/21403467/is-void-a-valid-return-value-for-a-function – orhtej2 Jun 23 '23 at 10:39
  • A `void` does not `return` anything. So simply remove `return` and it will work. Yes, if in the future you _do_ want to return something you will have to refactor. – oerkelens Jun 23 '23 at 10:40
  • Does this answer your question? [Is 'void' a valid return value for a function?](https://stackoverflow.com/questions/21403467/is-void-a-valid-return-value-for-a-function) – oerkelens Jun 23 '23 at 10:42
  • Each overload can CALL another overload but it cannot RETURN the result of that call because there isn't one. Would you expect to be able to assign the result of a method declared `void` to a variable? If not, why would you expect to be able to return it? – jmcilhinney Jun 23 '23 at 10:51

2 Answers2

0

I really don't know what is the problem you are having.

The following:

public void Something() => Console.ReadLine();

compiles just fine.

 public void AppendMessage(string styleKey, string? title, string body) {
        Debug.Assert(MessageFormatsMap.ContainsKey(styleKey));
// instead        return AppendMessage(MessageFormatsMap[styleKey], title, body); ;

AppendMessage(MessageFormatsMap[styleKey], title, body); // this will work
    }

// this also should work fine:
public void AppendMessage(string styleKey, string? title, string body) => 
   AppendMessage(MessageFormatsMap[styleKey], title, body);

Just calling the function will execute it, you don't need to return its result. AppendMessage being void means there is no result, so you cannot return "a thing".

Krzysztof Skowronek
  • 2,796
  • 1
  • 13
  • 29
  • the point is to not have to go in every overload to prepend a "return" in front of the AppendMessage() calls once i will switch their type from void to MyClass – Andrea Bardelli Jun 23 '23 at 12:56
  • then just chagne them? once you have the return, the compiler will tell you about the type mismatch. All you have to do is go to the line with error, alt-enter -> enter, done. It's called refactoring and you will be doing quite a lot of that. There is no escape from it. And if you know that you will change them, why not give them return type right away? C# doesn't have type inference for methods, they must be explicitly typed - sometime you will need to change the types. It's not a lot of work – Krzysztof Skowronek Jun 23 '23 at 13:44
0

I was wondering if there was some syntax that allowed me to leave the return voidReturningMethod() there ...

No, there is no such trick. If Proposal: Allow Void type as a Generic parameter will ever be accepted and implemented the you would be able to pass void to your generic class type parameter, i.e.:

class Base<T>
{
    T doStuff(int a) => doStuff(a.ToString());
    T doStuff(string b) => doStuff(null, b);

    T doStuff(string? a, string b)
    {
        T ret = RealComputation(); // real computation
        return ret;
    }

    protected virtual T RealComputation() => default;
}

class Child : Base<void>
{
}

Before that you are limited to workarounds like:

class Child : Base<MyVoid>
{
    protected override MyVoid RealComputation()
    {
        RealComputationVoid();
        return new MyVoid();
    }
    
    protected virtual void RealComputationVoid() {}
}
public struct MyVoid{}
Guru Stron
  • 102,774
  • 10
  • 95
  • 132