2

I have a simple value type MyTestStruct which has one method called Parse which attempts to convert a string into MyTestStruct:

public struct MyTestStruct {

   public readonly long UnderlyingValue;

   public MyTestStruct(long underlyingValue) 
   {
      UnderlyingValue = underlyingValuel
   }


   public static MyTestStruct Parse(string input) {
      if (string.IsNullOrEmpty(input))
          throw new ArgumentException("Value cannot be parsed because the string is either null or empty", nameof(input));
      return new MyTestStruct(long.Parse(input));
   }

}

VS 2019 has greeted me with the following warning:

Method 'MyTestStruct MyTestStruct.Parse(string input)' passes a literal string as parameter 'message' of a call to 'ArgumentException.ArgumentException(string message, string paramName)'. Retrive the following string(s) from a resource table instead: "Value cannot be parsed becase the string is either null or empty"'

Online search seem mostly focus on suppressing the warning but I would rather fixing it. Instead, I would like to be able to localize the string.

One solution would be to inject IStringLocalizer<MyTestStruct>, but it seems a bit odd to have an extra dependency in the struct only to use it 'if things go wrong'. Especially, as this is not alawys possible (e.g. implict conversions, operators etc). IStringLocalizer<MyTestStruct> can be mutable which is generally regarded as bad practice.

What would be the correct approach to take to fix this issue?

Dawid O
  • 6,091
  • 7
  • 28
  • 36
  • 1
    It mentions a "resource table" so it looks like things haven't changed from .NET Framework to .NET Core. Each BCL assembly uses an internal `SR` (string resource) class to retrieve localized strings. The analyzer probably expects you to do something similar. (ref [ArgumentNullException](https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/ArgumentNullException.cs#L34)) – madreflection Oct 28 '19 at 18:34
  • I'm not convinced that you should be translating a message like "Value cannot be parsed because the string is either null or empty" - since you will likely wind up with a message which is not intelligable to the user (who doesn't speak "Programmerese") nor to the engineer who receives the error message in a bug report (who doesn't speak the language into which the error message was translated). – Matthew Watson Oct 28 '19 at 18:47
  • @MatthewWatson this is not production code. I've installed FxCop in one of my pet projects and I'm working through the warning to see how to fix them – Dawid O Oct 28 '19 at 18:59
  • Ah, then as madreflection says, just add some string resources use those, same as in .Net Framework. – Matthew Watson Oct 28 '19 at 21:46
  • Not sure about best practice here. I have never bothered at a domain level. You can add `dotnet_diagnostic.CA1303.severity = none` to an [.editorconfig](https://learn.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019) file to remove this. – Andez Nov 26 '19 at 22:04
  • Not sure if this is what are you looking for : https://stackoverflow.com/questions/40526908/do-not-pass-literals-as-localized-parameters – Was Jan 23 '20 at 07:36

1 Answers1

1

You can add the string literals in project's "Resource table" and use those via instance of ResourceManager in your program. It would be easy if you are using Microsoft Visual Studio IDE and a bit difficult if you go by command line tool(ref MS docs CA1303 & ResourceManagerClass). In Visual Studio solution explorer, expand your project > Properties. Find Resources.resx file and double click to open the "Resource table". You will see 3 columns - Name, Value, Comment. In the Name column, define a short name for your string literal. In the Value, put your entire string literal and in comments anything related you would like. Once the string literals are set in the Resource table, you need to create an object of ResourceManager as defined below.

// to include the Resources library
using System.Resources; 
// Create an instance of ResourceManager class
ResourceManager resourceManager = new ResourceManager("<YourProjectName>.Properties.Resources", typeof(Properties.Resources).Assembly);
// CultureInfo instance to be used for ResourceManager
CultureInfo cultureInfo = CultureInfo.CurrentUICulture;
// Retrieve and assign the string literal value from the Resource table
input = resourceManager.GetString("<Name column value here>", cultureInfo); 
Ankit4154
  • 11
  • 2