As documented in the Boolean.ToString(IFormatProvider) method doc, the IFormatProvider provider does not impact the constant "True/False" output.
Now, is there a way to however translate the "True" to "Verdadero"?
public static void Main(string[] args)
{
//Your code goes here
Console.WriteLine("Hello, world!");
System.Globalization.CultureInfo ci = new CultureInfo("es-ES");
Console.WriteLine(true.ToString(ci));
}
// Hello, world!
// True
There isn't a library-based solution to your question, nor should there be. The reason is that a string representation of System.Boolean is unlikely to be useful for anything but the most trivial of localization. Note that is not the case for floating-point numbers where a culture-specific . or , can be applied when formatting. Dates (System.DateTime) have some localization support from the operating system itself, so .NET is able to build on that; this is not the case for System.Boolean.
Usually, there will be other words in addition to just "True" (or "False"); those words will have to be translated too. And, depending on the language and those other words, you might not be able to do simple string concatenation: string message = baseMessage + b.ToString();
Instead, you should store your strings in resource files and retrieve the right one.
bool b = ...;
string message = b ? Properties.Resources.TrueMessage : Properties.Resources.FalseMessage;
See How to use localization in C# for more details.
As per the docs, Boolean.ToString(IFormatProvider) will not reflect culture specific strings.
However, one workaround could be to create an extension method on the Boolean object:
public static class BoolExtensions
{
public static string ToSpanishString(this bool val)
{
return val ? "Verdadero" : "Falso";
}
}
You can achieve this in the following way:
bool test = true;
Console.WriteLine(test ? "Verdadero" : "Equivocado");
The first value is always the truthy one, the second is the falsy.
Related
I just discovered this nice tool XmlUnit that allows me to evaluate 2 different XML documents and display the eventual discrepencies.
string control = "<a><b attr=\"abc\"></b></a>";
string test = "<a><b attr=\"xyz\"></b></a>";
var myDiff = DiffBuilder.Compare(Input.FromString(control))
.WithTest(Input.FromString(test))
.Build();
Assert.IsFalse(myDiff.HasDifferences(), myDiff.ToString());
However, I have found that the myDiff.ToString() only displays the first difference encountered.
Is there a way to display them all ?
I just found the solution
Assert.IsFalse(myDiff.HasDifferences(), string.Join(Environment.NewLine, myDiff.Differences));
I assume that you are using the xmlunit.net library (You didn't say the name of the tool that you found but your example seems to match).
You can search their GitHub repo and find the DiffBuilder class file. If you look at the Build method you will see it returns a Diff object. If you go to the Diff class file you will find that it's ToString method looks like this.
public override string ToString() {
return ToString(formatter);
}
Which doesn't tell you a lot but if you go to the other ToString overload you find this.
public string ToString(IComparisonFormatter formatter) {
if (!HasDifferences()) {
return "[identical]";
}
return differences.First().Comparison.ToString(formatter);
}
Now we are getting somewhere. We now know that Diff stores its list of differences in a private differences field and why ToString() only returns one difference (The .First() call). If you look through that class you will find that there's a public property called Differences which exposes that field as an IEnumerable. So the way to get all differences is to loop through that property and collect all of them like so.
string control = "<a><b attr=\"abc\" attr2=\"123\"></b></a>";
string test = "<a><b attr=\"xyz\" attr2=\"987\"></b></a>";
var myDiff = DiffBuilder.Compare(Input.FromString(control))
.WithTest(Input.FromString(test))
.Build();
var sb = new StringBuilder();
foreach(var dif in myDiff.Differences)
{
sb.AppendLine(dif.Comparison.ToString());
}
Assert.IsFalse(myDiff.HasDifferences(), sb.ToString());
Note that I got the syntax for formatting the difference from the Diff class's ToString code. Also notice that I added a second attribute to your examples to demonstrate that this really is showing all the differences.
In C# 6 what is the default culture for the new string interpolation?
I've seen conflicting reports of both Invariant and Current Culture.
I would like a definitive answer and I'm keeping my fingers crossed for Invariant.
Using string interpolation in C# is compiled into a simple call to String.Format. You can see with TryRolsyn that this:
public void M()
{
string name = "bar";
string result = $"{name}";
}
Is compiled into this:
public void M()
{
string arg = "bar";
string text = string.Format("{0}", arg);
}
It's clear that this doesn't use an overload that accepts a format provider, hence it uses the current culture.
You can however compile the interpolation into FormattbleString instead which keeps the format and arguments separate and pass a specific culture when generating the final string:
FormattableString formattableString = $"{name}";
string result = formattableString.ToString(CultureInfo.InvariantCulture);
Now since (as you prefer) it's very common to use InvariantCulture specifically there's a shorthand for that:
string result = FormattableString.Invariant($"{name}");
I have a service that validates the user input. So, in other layers I am just using the below statement to get the amount value assuming that it is already validated.
But while writing unit test cases, I realized this is failing. So, my question is do we need to ALWAYS try to parse the values whenever string values needs to be converted to actual types.
var amountValue = Convert.ToDecimal(string.Format("{0}.{1}", view.amount, view.fraction))
You should parse strings because that's what you actually want to do.
A type conversion is something different than parsing.
Imagine a case where in the US you separate decimals with a dot . and in EU you'd use a comma ,. You can't really know how the locale separates decimals and whatnot (especially dates are crucial and should be PARSED no CONVERTED).
That said, the rule user input => parse is quite straight forward.
Here is a convert method based on generics:
public static void Convert<T>(string text, out T value, CultureInfo culture) where T : IConvertible
{
if (typeof(T).IsEnum)
{
value = (T) Enum.Parse(typeof (T), text, true);
}
else
{
value = (T)System.Convert.ChangeType(text, typeof(T), culture);
}
}
I have the following extension method
public static bool IsValidCurrency(this string value)
{
CultureInfo culture = new CultureInfo ("en-gb");
decimal result;
return decimal.TryParse(value, NumberStyles.Currency, culture, out result);
}
I wish to have this to be culturally neutral allowing to pass $ , €, ¥ etc. into the method
Thanks
Different cultures may use the same currency symbol to mean different things. Hence there is no invariant way to read a currency.
It could however be done in the following way:
public static bool IsValidCurrency(this string value)
{
decimal result;
var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
return cultures.Any(info => Decimal.TryParse(value, NumberStyles.Currency, info, out result));
}
My initial thought is that passing in a currency symbol to such a method without context means it might be a valid symbol, but not necessarily the correct one - many regions use the '$' symbol, for example.
If I were doing this anyway, I'd probably loop round the specific .NET cultures (avoiding the Invariant Culture, if you're on Windows 7), checking each RegionInfo's CurrencySymbol property against the string passed in. This is quick, dirty (and untested) while it's still in my head; I'm sure this could be more efficiently coded:
public static Boolean IsValidCurrency(this string value)
{
// Assume the worst.
Boolean isValid = false;
foreach (CultureInfo c in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
// Account for InvariantCulture weirdness in Windows 7.
if (!c.Equals(CultureInfo.InvariantCulture))
{
RegionInfo r = new RegionInfo(c.LCID);
if (r.CurrencySymbol.Equals(value, StringComparison.OrdinalIgnoreCase))
{
// We've got a match, so flag it and break.
isValid = true;
break;
}
}
}
return isValid;
}
This assumes you're only passing in the symbol, and doesn't solve the variant uses of different symbols. Hope this gets you thinking, anyway.
In C#, I have a width I want to use for some strings, but I won't know that width until runtime. I'm doing something like this:
string.Format("{0, " + digits + "}", value) // prints 123 as " 123"
Is there a string formatting directive that lets me specify this without smashing my own format string together like this?
I looked around on MSDN for a little while and I feel like I'm missing a whole chapter on format strings or something.
Take a look at PadLeft:
s = "123".PadLeft(5); // Defaults to spaces
s = "123".PadLeft(5, '.'); // Pads with dots
You can use the PadLeft and PadRight methods:
http://msdn.microsoft.com/en-us/library/system.string.padleft%28VS.71%29.aspx
you can do something like
string test = valueString.PadLeft(10,' ');
or even sillier
string spaces = String.Concat(Enumerable.Repeat(" ", digits).ToArray());
The functions mentioned by others will work, but this MSDN page has a more general solution to formatting that changes at runtime:
Composite Formatting
They give examples much like yours.
Edit: I thought you were trying to solve the general case of composing a format string at runtime. For example, if there were no built in PadLeft(), you could do this:
int myInt = 123;
int nColumnWidth = 10;
string fmt = string.Format("Price = |{{0,{0}}}|", nColumnWidth);
// now fmt = "Price = |{0,5}|"
string s = string.Format(fmt, myInt);
You can even do all that in one line, but it's ugly:
string s = string.Format(
string.Format("Price = |{{0,{0}}}|", nColumnWidth),
myInt);
Perhaps this will help with your research on formatting:
Formatting Types
Composite Formatting
However, I don't think you're going to do much better than this, as the alignment parameter must be part of the format string and does not seem to be represented by a property.
Probably overkill but just to illustrate a way to encapsulate the format specification and use an overload of String.Format that accepts an IFormatProvider.
class Program
{
public static void Main(string[] args)
{
int digits = 7;
var format = new PaddedNumberFormatInfo(digits);
Console.WriteLine(String.Format(format, "{0}", 123));
}
}
class PaddedNumberFormatInfo : IFormatProvider, ICustomFormatter
{
public PaddedNumberFormatInfo(int digits)
{
this.DigitsCount = digits;
}
public int DigitsCount { get; set; }
// IFormatProvider Members
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
return null;
}
// ICustomFormatter Members
public string Format(string format, object arg, IFormatProvider provider)
{
return String.Format(
String.Concat("{0, ", this.DigitsCount, "}"), arg);
}
}
I posted a CodeProject article that may be what you want.
See: A C# way for indirect width and style formatting.
Basically it is a method, FormatEx, that acts like String.Format, except it allows for indirect alignment and formatString specifiers.
FormatEx("{0,{1}:{2}}", value, width, formatString);
Means format the value of varArgs 0, in a field width specified by varArgs 1, using a formattingString code specified by varArgs 2.
Edit: Internally, it does what many others have suggested in their answers. I've just wrapped the parsing and determination of the final values to use for alignment and formatString. I also added a "center alignment" modifier.
-Jesse
String has a constructor that creates a string with a given character repeated n times.
https://msdn.microsoft.com/en-us/library/xsa4321w(v=vs.110).aspx
// prints 123 as " 123"
string.Format(new string(' ', digits) + "{0}", value)