Specifying locale for string interpolation in C#6 (Roslyn CTP6) - c#

String interpolation in C#6 lets me write:
decimal m = 42.0m;
string x = $"The value is {m}";
However, a very common use case for string formatting is to specify the locale used for formatting the values. Let's say I need to use InvariantCulture for the formatting operation above, what is the syntax for that ?
This discussion suggests that I should be able to do this:
string x = INV($"The value is {m}");
Where INV is defined as
public static string INV(IFormattable formattable)
{
return formattable.ToString(null, System.Globalization.CultureInfo.InvariantCulture);
}
However, this does not work. It compiles, but it leaves my program hanging at in cmd.exe at startup - as if klr.exe, that I assume is being invoked, hangs (Compiler bug?)
This is an ASP.NET 5 Console Project in VS15 CTP 6.

What you have should work. It's the correct syntax. There's also a convenient method on the "System.FormattableString" abstract class which has the same effect as the suggested "INV" helper method.
using static System.FormattableString;
...
string x = Invariant($"The value is {m}");

I finally figured this out. As it turns out, the compiler feature relies on two types, System.FormattableString, and System.Runtime.CompilerServices.FormattableStringFactory. These were not available for my project - I guess they might not yet have made it into all platforms for CTP6.
This apparently made the compiler hang as described. Once I pulled the code for those two types from the CoreCLR code and added it to my project, my code works as expected.
This was figured out through code comments for the InterpolationTests. Hooray for the source being available :-)

Related

C# - Make a new class not part of System.Object

I have a huge code base and I recently made a change where I changed the type of a parameter from String to a custom class. On the next compile I got all the areas where the impact was, but areas where the input type was of type Object failed. for e.g.
String str = "32"
int i = Convert.ToInt32(str)
Now I have changed String to a new custom type lets say MyCustomClass I would now want following code to fail on next compile
MyCustomClass str = new MyCustomClass("32")
int i = Convert.ToInt32(str)
but it won't as Convert.ToInt32 also accepts type Object. Is there some way I can make a change in MyCustomClass that it's not considered Object anymore.
Please note: Convert.ToInt32 is only used for sample I have many more such functions, so please focus your suggestion/answer to question asked.
Override ToString() and IConvertible
You said in the comments that your intentions are to find places where your object, which had previously been treated as a string, and are now being treated as an object.
In these situations typically, the third-party code would call .ToString() on your object to get something which it can use.
So, Convert.ToInt32(str) is equivalent to Convert.ToInt32(str.ToString()).
If you implement ToString() and IConvertible to return whatever your old version of str looked like then it should continue to work in the same way as the old version.
Probably.
Sorry I know that is not the 100% perfect compile time answer you were looking for, but I think you also know very well that your MyCustomClass will always be considered object.
Possible compile time answer:
Write a tool which uses reflection to iterate over every class/struct/interface in every system/third-party DLL.
Output a load of CS files which contain all these same classes, but just throw NotImplementedException.
(T4 could help you do this)
Compile these classes into dummy.dll
Your .csproj now references only this one dummy.dll, instead of the real dlls.
Your project should compile fine against the dummy dll.
Look at your dummy.cs files and delete any use of object.
Re-compile... and suddenly you get a load of compile time errors showing you anywhere you are using an object.
Impliment an implicit cast from MyCustomClass to String.
public static implicit operator string(MyCustomClass str)
{
return "Legacy respresentation of str";
}
This allows the complier the choice of choosing ToInt32(Object) or ToInt32(String), and I bet it favours the later.
This way all your existing function calls will remain the same so you wont have to be concerned about third party implentation details.
(Sorry, I am not at a computer right now so I can`t test that my assumtion is correct. If you do test this, be sure to consider extension methods, as they can affect the conpilers desision making in unexpected ways)

Enum.GetName() As Constant property

I have been working in C# for about 8 months so forgive me if this is dumb...
I have an enum that I will need the string value several times in a class. So I want to use Enum.GetName() to set it to a string variable which is no problem. I just do it like so...
private string MyEnumString = Enum.GetName(typeof(MyEnum), MyEnum.Name);
And it works just fine.
But I tried to protect it a little better because this particular Enum is more important that all the others and it would not be good if I accidentally changed the string value somehow so I tried to make it const like this.
private const string MyEnumString = Enum.GetName(typeof(MyEnum), MyEnum.Name);
To my eyes this seems fine as it should all be known at compile time.
But Visual Studio 2013 Throws an error saying the "Cannot resolve symbol GetName". I know it works when it is not marked "const".
So this leads me with two questions about this?
Why does it loose reference to the GetName enum? (After a bit of research I suspect it is something to do with GetName being a method and not a property of the Enum class but the error message just does not make sense to me)
And Finally is there a way to read the Name of MyEnum.Name to a const string other than what I am doing?
Just make it readonly:
private readonly string MyEnumString = Enum.GetName(typeof(MyEnum), MyEnum.Name);
Then it can't be changed afterwards.
You can't assign the result of calling a method to a constant; C# just doesn't allow it - the compiler would have to be calling that method at compile time, possibly before it was even compiled (and not only would it have to generate the IL, it would have to use the JIT compiler to compile that IL).
Enum.GetName(typeof(MyEnum), MyEnum.Name); is calling a method, so you can't assign the result to a constant.
[EDIT] As Jon Skeet says in a comment above, you can use nameof if using C#6 or later (i.e. VS2015 or later):
private const string MyEnumString = nameof(MyEnum.Name);
nameof works because here you are not calling an arbitrary method, but you are instead using a compiler feature to access the name of a type.
You cannot use result of the method as constant, because method evaluation can occur only at runtime. The value of the constant must be known at compile time. In order for compiler to be able to evaluate that constant, it would need to know the semantics of Enum.GetName and execute it at compile time, which is not possible
You can mark it as static readonly instead. That way it will be set once per type where it is declared and it cannot be changed anymore at runtime.
It may not even be known at run-time:
From MSDN:
If multiple enumeration members have the same underlying value, the GetName method guarantees that it will return the name of one of those enumeration members. However, it does not guarantee that it will always return the name of the same enumeration member.
(emphasis added)
void Main()
{
Console.WriteLine (Enum.GetName(typeof(Test),Test.One));
}
public enum Test
{
Zero,
One,
Two,
Uno = 1,
Dos = 2,
}
I consistently get the output Uno for the program above.
The reason is it not known is because enums are compiled to the underlying value. The call above is essentially compiled to Enum.GetName(typeof(Test), 1). GetName looks for a member with that value to find the name. How it does that is apparently an implementation detail that may not product consistent results.
What you can use for a constant in C#6 and later is nameof:
private const string MyEnumString = nameof(MyEnum.Name);

C# default parameters workaround

Is there a workaround for default parameters? In C++ I would use
int foo(int k, bool check = false)
A tedious workaround would be to overload a function. An easier one? (There is no way just adding the variable and checking the calls of the function!!)
Thanks,
Sun
The C# (before 4.0) didn't support the default parameters. Even in c# 4.0 the default parameters are a bit different than in C++ - they're stored in metadata and, when you reference the assembly with default parameters, they're compiled into your code. So, if the default value was changed in the future, your code will still pass the OLD default value, which may cause the bad effect. So, use the overloaded functions with a single parameter and double parameters and call the one with more parameters passing the default value. Such approach will have a least side effect.
In C#4, you can do the same. So this is allowed:
int foo(int k, bool check = false){
...
}
There are also possible to use named arguments in C#4 so you can call this method in many different ways:
foo(10, true);
foo(10);
foo(k: 10, check: true);
foo(check: true, k: 10);
named arguments are useful if you have several optional parameters, and only want to specify one of them that is not the first optional one, or to improve readability on the calling side.
In C# 4.0 default and named parameters is supported now.
http://msdn.microsoft.com/en-us/library/dd264739.aspx
You can use optional parameters in your assemblies if they are build with MSBuild 4.0 (VS2010) even if you are targeting the .Net 2.0 framework.
The syntax is just like you said:
int foo(int k, bool check = false)
{
}
To elaborate on Denis Mazourick's answer about using default optional parameters in C# 4.0 and how the default values get compiled into the consuming class, try this.
Create a class library with the following code and build it:
public class ClassWithDefaultParameters {
public string Msg { get; set; }
public ClassWithDefaultParameters(string msg = "Hello World") {
Msg = msg;
}
}
public class ClassWithConstructorOverloads {
public string Msg { get; set; }
public ClassWithConstructorOverloads(string msg) {
Msg = msg;
}
public ClassWithConstructorOverloads() : this("Hello World") {}
}
Now create a console application and reference the dll you just built (not the project, but the actual dll). Place this in your code and build the console application.
static void Main() {
var cwdp = new ClassWithDefaultParameters();
var cwco = new ClassWithConstructorOverloads();
Console.WriteLine(cwdp.Msg);
Console.WriteLine(cwco.Msg);
}
When you run the application, the output will be as you expected:
Hello World
Hello World
Now open up the class library, and change both "Hello World" in "Hello Europe". Recompile the library and copy the dll to the output folder of the console application. Do not rebuild the console application.
When you run the console application again, the output will be:
Hello World
Hello Europe
Probably not what you expected! It's not until you rebuild the console application that both lines will print Hello Europe.
I didn't know this and I think I won't use the default parameters because of this. What's worse is that Microsoft doesn't mention this on the MSDN page.
well, there is no easier way, you could use param feature, but it is risky as well.
have a look at example for string.Format() where you can use it like:
stringA.Format("{0} is {1}", str1, str2)
that way you can pass any number of params, but it is quite tricky how u consume it and could be quite error prone

Is there .net magic to get parameter values by name in console application?

I've been developing .net console applications using C# and have always just dictated what order parameters must be inserted in so that args[0] is always start date and args[1] is always end date, for example.
however I would like to move over to using named parameters so that any combination of parameters can be sent in any order, such as the typical "-sd" would prefix a start date.
I know I could parse through the args[] looking for "-" and then read the name and look the next position for the accompanying value, but before doing that wanted to see if there was any kind of baked in handling for this rather standard practice.
is there something like this out there already that could do as such:
DateTime startDate = (DateTime)((ConsoleParameters)args[])["sd"]
I'm using C# and .Net 4
There is nothing built into the core framework.
A lot of people think NDesk.Options is useful for this sort of thing. Check out this example (taken directly from the provided link):
string data = null;
bool help = false;
int verbose = 0;
var p = new OptionSet () {
{ "file=", v => data = v },
{ "v|verbose", v => { ++verbose } },
{ "h|?|help", v => help = v != null },
};
List<string> extra = p.Parse (args);
Yes, the "magic" is that this is a common problem and it has been adequately solved. So I recommend using an already written library to handle parsing command line arguments.
CommandLineParser has been great for me. It is reasonably documented and flexible enough for every type of command line argument I've wanted to handle. Plus, it assists with usage documentation.
I will say that I'm not the biggest fan of making a specific class that has to be adorned with attributes to use this library, but it's a minor point considering that it solves my problem. And in reality forcing that attributed class pushes me to keep that class separate from where my app actually retrieves it's settings from and that always seems to be a better design.
You can use NDesk.Options.
There is no such a thing as named parameters. "-sd" is just a choice for a specific application. It can be "/sd" as well. Or "sd=". Or whatever you want.
Since there are no named parameters, there is nothing inside .NET Framework which let you use the "-sd" syntax.
But you can quite easily build your own method to get a set of "named parameters" for your app.
Edit: or, even better, you can use an existing library, like suggested in other answers.
Edit: reading the answer by #Sander Rijken, I see that I was wrong: there were still an implementation of "-sd" syntax in .NET 4.0 before the release. But since it was dropped before the final release, the only ways are still to create your own method or to use an existing library.

Add Ellipsis to a Path in a WinForms Program without Win32 API call (revisited)

I was searching for a way to insert an ellipsis in a C# path, and found an answer here on stackoverflow: C# Path Ellipsis without Win32 API call
Using the RTM versions of VS2010 and .Net 4.0, I was unable to get the suggested method to work. I searched the 'Net and found example code that uses the same method, but it failed in the same way.
You can see the string I'm trying to shorten in my code below.
After calling the MeasureText method, both the input string (OriginalName) and the output string (ellipsisedName) look like this:
d:\abcd\efgh\ijkl\mnop\qrst\...\test.txt\0F\GHIJ\KLMN\OPQR\STIV\WXYZ\test.txt
Two problems:
1) The resulting string is narfed (the path is truncated as expected, but is followed by what looks like a C-style terminating null and a chunk of the original path).
2) My original string is changed to be identical to the output string.
Am I doing something wrong?
namespace WindowsFormsApplication2 {
public partial class Form1 : Form {
public Form1()
{
InitializeComponent();
string OriginalPath = #"d:\abcd\efgh\ijkl\mnop\qrst\uvwx\yzAB\CDEF\GHIJ\KLMN\OPQR\STIV\WXYZ\test.txt";
string ellipsisedPath = OriginalPath;
Size proposedSize = new Size(label1.Width, label1.Height);
TextRenderer.MeasureText(ellipsisedPath, label1.Font, proposedSize, TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis);
}
}
}
Holy moly, you've found a whopper of a bug. The P/Invoke used inside the TextRenderer class that calls DrawTextEx() is borked. That API function is writing back into the string, which it is allowed to do since the cchText argument is a LPTSTR, not a LPCTSTR. That destroys the .NET string content for both variables because the string is interned.
The bug isn't specific to .NET 4.0, I see it wrong in the ReferenceSource for .NET 3.5 SP1 as well and can repro it on VS2008. The trouble is in the internal WindowsGraphics.MeasureText function. You can report the bug at connect.microsoft.com.
A possible workaround is to alter the string so it gets copied and can't affect the original:
string ellipsisedPath = OriginalPath + '\0';
But the better workaround in this case is to simply not pass the ModifyString option, it serves no purpose. Which is safer too, there is still a possibility of destroying the garbage collected heap with the first workaround. The fix for Microsoft is similarly simple, it should just mask out the ModifyString option. It is documented to have no effect.
My original string is changed to be identical to the output string.
You've asked for this to happen by specifying TextFormatFlags.ModifyString, which the docs say
Modifies the specified string to match the displayed text. This value has no effect unless EndEllipsis or PathEllipsis is also specified.
This is (to my mind) an unusual way for a .NET Framework call to operate, but it does clearly say it will do this. Both the 'original' string and the 'output' string end up being modified, because string is a reference type (though usually with immutable value semantics) - when you say
string ellipsisedPath = OriginalPath;
you are actually just making ellipsisedPath refer to the same string instance as OriginalPath does. When this instance gets modified by the API call, both the references to it will see the modification.
As for
the path is truncated as expected, but is followed by what looks like a C-style terminating null and a chunk of the original path
my guess would be that the abstraction this managed wrapper provides around the Win32 API call is being somewhat leaky, as abstractions are prone to being - it's not shielding you from the fact that the underlying call works with C-style strings. It might be that you'll have to deal with yourself.

Categories