Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FP: SA1205 for partial, file-scoped classes #3906

Open
CaringDev opened this issue Nov 26, 2024 · 9 comments
Open

FP: SA1205 for partial, file-scoped classes #3906

CaringDev opened this issue Nov 26, 2024 · 9 comments

Comments

@CaringDev
Copy link

SA1205 fires for partial file-scoped classes:

file partial class SA1205
{
}
@bjornhellander
Copy link
Contributor

Interesting case 😄 Do you have an actual use case for file partial, or was this more of an accidental discovery?

@CaringDev
Copy link
Author

CaringDev commented Nov 26, 2024

:-D I do
Trying to switch a logging statement of a private inner class to a source-generated method:

public class Outer
{
  // ... some use of Inner ...
  private class Inner
  {
    // ...
      logger.LogWarning(...)
    // ...
  }
}

then

public class Outer
{
  // ... some use of Inner ...
  private class Inner // if partial: requires Outer to be partial
  {
    // ...
    [LoggerMessage(...)]
    private static partial void Log(...)  // requires Inner to be partial
  }
}

so, I thought, let's use the new file-scope:

public class Outer
{
  // ... some use of Inner ...
}

file sealed partial class Inner // even if partial, does NOT require Outer to be partial
{
  // ...
  [LoggerMessage(...)]
  private static partial void Log(...)  // requires Inner to be partial
}

Addendum, see #3906 (comment) ff.
However, this does not even compile... so is rather artificial.

@julealgon
Copy link

Just out of curiosity @CaringDev , why do you want the generated log methods to be in an inner class (or on a friend class in your second example using file), instead of just having them in the parent class directly?

Is it purely an organizational thing on your side, or is there more to it?

Just to be sure... you realize you don't need the autogenerated log methods to be static, correct?

@CaringDev
Copy link
Author

CaringDev commented Nov 26, 2024

@julealgon
If the logging methods were in the parent Outer class, they would need to be accessible from Inner... obviously the real code is a bit more complex :-)
The method needs to be static though: https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib1009

@julealgon
Copy link

@CaringDev

@julealgon If the logging methods were in the parent Outer class, they would need to be accessible from Inner... obviously the real code is a bit more complex :-)

Fair enough.

The method needs to be static though: https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib1009

That warning is incorrect:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var hostBuilder = Host.CreateApplicationBuilder();
hostBuilder.Services.AddTransient<Service>();

var host = hostBuilder.Build();
var service = host.Services.GetRequiredService<Service>();

service.DoIt();

public partial class Service(ILogger<Service> logger)
{
    public void DoIt()
    {
        LogSomething();
    }

    [LoggerMessage("Something here.", Level = LogLevel.Information)]
    public partial void LogSomething();
}

Try this. No warnings and the log is emited properly.

info: Service[1256132127]
      Something here.

I would assume this warning is only used in specific circumstances, maybe when the parent class is itself static.

@CaringDev
Copy link
Author

@julealgon interesting... the generated logger callback is static in both cases. The analyzer might be about performance... to bad the rationale is not documented 🤷
In any case, the logger method being static or not is not relevant for SA1205.

@bjornhellander
Copy link
Contributor

I have tried a few examples I found online using the LoggerMessage attribute, but I can't get them to compile with the file keyword. And that is pretty much what I expected: Source generators generate new files. The file keyword makes the type accessible only from within the same file. That sounds like a bad combination. I don't see how you can possibly implement methods in a file class using a source generator. But I might very well be missing something.

Can you provide a small but complete class that compiles? Just trying to understand how relevant this combination of keywords is.

@CaringDev
Copy link
Author

@bjornhellander of course, you're absolutely right. I didn't even try to compile, once I got the SA-squigglies🤦
So this is only valid for partial classes within a single file, which is most likely not a real-world issue 😅

@bjornhellander
Copy link
Contributor

Ok, good. The fix is trivial and I have a draft ready. Since you have found it I personally think that we might as well fix it. But the pull requests are piling up right now, so I don't want to add another one at this moment for something that we right now don't have a reasonable use case for. I suggest we keep the issue open though, to possibly be handled later on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants