Champion "Support extension methods everywhere"
- [ ] Proposal added
- [ ] Discussed in LDM
- [ ] Decision in LDM
- [ ] Finalized (done, rejected, inactive)
- [ ] Spec'ed
See also https://github.com/dotnet/roslyn/issues/4565 I've labeled this "Proposal Champion" because it has been triaged by the LDM, but we don't actually have a champion at this point.
See also dotnet/roslyn#16271
We decided it would be easier on both programmers and the compiler if we limit the number of places that you have to look for extension methods.
If this is an issue it can be made to accept only private methods for non-static classes. I wish to be able to build fluent code that will only run inside the class.
Not being able to create extension methods in non-static classes prevents me from using dependency-injected logging inside the extension methods. This makes unit testing difficult and forces me to break things out into services, which adds more complexity than is called for.
Being able to do this would make things much simpler:
public class ModelConversionExtensions
{
private readonly ILogger<ModelConversionExtensions> _logger;
public ModelConversionExtensions(ILogger<ModelConversionExtensions> logger) => _logger = logger;
public static DataModel? ConvertToDataModel(this ViewModel vm)
{
try
{
return new DataModel() { foo_bar = vm.FooBar };
}
catch
{
_logger.LogError($"Could not convert {nameof(ViewModel)} with Id of {vm.Id} to {nameof(DataModel)}");
return null;
}
}
}
@stamminator
Not being able to create extension methods in non-static classes prevents me from using dependency-injected logging inside the extension methods.
A static member cannot access instance members without an instance. You cannot accomplish what you're describing without some kind of global state, which is pretty much faux pas in a dependency/unit paradigm. However, you could easily accomplish it via:
public static class ModelConversionExtensions
{
private static ILogger<ModelConversionExtensions> _logger = SomeDefaultLogger;
public static void RegisterLogger(ILogger<ModelConversionExtensions> logger) => _logger = logger;
public static DataModel? ConvertToDataModel(this ViewModel vm)
{
try
{
return new DataModel() { foo_bar = vm.FooBar };
}
catch
{
_logger.LogError($"Could not convert {nameof(ViewModel)} with Id of {vm.Id} to {nameof(DataModel)}");
return null;
}
}
}
@HaloFour You're totally right, that's my bad. Thanks for the suggestion. In your example, what does SomeDefaultLogger consist of, a global static logger? With the idea being that it needs something to start with, but ideally RegisterLogger should be getting called on app startup with DI?