Today i had a challenge with my College and i gaved up ,no idea how to achieve it .
Is there a way to declare a String ,as Constant and on Load Event maybe using Reflection to change String to non-Constant assign a value from XML ,than Change it to Constant again .
And all of the Code which does that (Constant to Non-Constant),should be Stored in a String ,and on Load before Type Change ,it should be Decrypted and Injected into the Application .
example:
private const String RegNumber = "";
//Change RegNumber to Writable String
//Change RegNumber value
//Than Change RegNumber back to const again
PS : Please sorry but i have no idea where to start ,and show here some code .
You can't declare it as const but you can declare it as static readonly:
private static readonly string Foo = ReadValueFromAssembly();
static string ReadValueFromAssembly()
{
// Perform your logic and return the string here
}
Would that do everything you need? It's not really clear what you mean about the "code which does that [...] should be decrypted and injected into the application" but you can make the above method do anything you need it to as normal.
As a side-note, it's generally a bad idea to do a lot of work in a type initializer like this.
EDIT: You can store code as a string, use CSharpCodeProvider to compile it at execution time, and then execute the compiled code. I have a sample of this in "Snippy" which I used for C# in Depth as a quick tool for compiling snippets.
It may not even exist at runtime, the compiler could have just replaced all usages of it with their literal values (in fact, it probably has, though I don't think it's required to by the standard).
So no, I don't see how this could be possible.
It is theoratically possible. See
How to programmatically compile code using C# compiler
http://support.microsoft.com/kb/304655
You can write the code in a string and compile using the API mentioned in above article.
I have not done that before but it should give you an idea on how to start.
Also see,
Can I change value of constant in C#?
Related
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)
Scenario
I have a class for declaring string constants used around a program:
public static class StringConstants
{
public const string ConstantA = "ConstantA";
public const string ConstantB = "ConstantB";
// ...
}
Essentially, it doesn't matter what the actual value of the constant is, as it used when assigning and consuming. It is just for checking against.
The constant names will be fairly self-explanatory, but I want to try and avoid using the same string values more than once.
What I would like to do
I know that nameof() is evaluated at compile-time, so it is entirely possible to assign the const string's value to the nameof() a member.
In order to save writing these magic strings out, I have thought about using the nameof() the constant itself.
Like so:
public static class StringConstants
{
public const string ConstantA = nameof(ConstantA);
public const string ConstantB = nameof(ConstantB);
// ...
}
Question...
I guess there is no real benefit of using the nameof(), other than for refactoring?
Are there any implications to using nameof() when assigning constants?
Should I stick to just using a hard-coded string?
Whilst I think the use of nameof is clever, I can think of a few scenarios where it might cause you a problem (not all of these might apply to you):
1/ There are some string values for which you can't have the name and value the same. Any string value starting with a number for example can't be used as a name of a constant. So you will have exceptions where you can't use nameof.
2/ Depending how these values are used (for example if they are names of values stored in a database, in an xml file, etc), then you aren't at liberty to change the values - which is fine until you come to refactor. If you want to rename a constant to make it more readable (or correct the previous developer's spelling mistake) then you can't change it if you are using nameof.
3/ For other developers who have to maintain your code, consider which is more readable:
public const string ConstantA = nameof(ContantA);
or
public const string ConstantA = "ConstantA";
Personally I think it is the latter. In my opinion if you go the nameof route then that might give other developers cause to stop and wonder why you did it that way. It is also implying that it is the name of the constant that is important, whereas if your usage scenario is anything like mine then it is the value that is important and the name is for convenience.
If you accept that there are times when you couldn't use nameof, then is there any real benefit in using it at all? I don't see any disadvantages aside from the above. Personally I would advocate sticking to traditional hard coded string constants.
That all said, if your objective is to simply to ensure that you are not using the same string value more than once, then (because this will give you a compiler error if two names are the same) this would be a very effective solution.
I think nameof() has 2 advantages over a literal strings:
1.) When the name changes, you will get compiler errors unless you change all occurences. So this is less error-prone.
2.) When quickly trying to understand code you didn't write yourself, you can clearly distinguish which context the name comes from. Example:
ViewModel1.PropertyChanged += OnPropertyChanged; // add the event handler in line 50
...
void OnPropertyChanged(object sender, string propertyName) // event handler in line 600
{
if (propertyName == nameof(ViewModel1.Color))
{
// no need to scroll up to line 50 in order to see
// that we're dealing with ViewModel1's properties
...
}
}
Using the nameof() operator with public constant strings is risky. As its name suggests, the value of a public constant should really be constant/permanent. If you have public constant declared with the nameof() and if you rename it later then you may break your client code using the constant. In his book Essential C# 4.0, Mark Michaelis points out: (Emphasis is mine)
public constants should be permanent because changing their value will
not necessarily take effect in the assemblies that use it. If an
assembly references constants from a different assembly, the value of
the constant is compiled directly into the referencing assembly.
Therefore, if the value in the referenced assembly is changed but the
referencing assembly is not recompiled, then the referencing assembly
will still use the original value, not the new value. Values that
could potentially change in the future should be specified as readonly
instead.
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);
I have a small c# class, that does some logging stuff and that is called from a powershell scripting framework using:
[System.Reflection.Assembly]::LoadFrom("$ExtensionsPath\LogWriter.dll")
$Log = New-Object LogWriter($LogFile, $addTimeStamp, $logLevel, $overWrite)
Writing into the log file goes like this
$Log.AddInfo("myText")
Works fine so far.
What I am thinking about for some time is, if I am able to use stringexpansion in the AddInfo() method of my LogWriter class?
Look at the example:
$ModulesPath = ‘C:\temp\modules’
$test = ‘This is a text and I want to expand $ModulesPath in my c# LogWriter class’
$Log.AddInfo($test)
The c# class shall now expand the $modulespath in $test as powershell does. I already know that in c# I have access to the powershell runspace from which the c# class was called using System.Management.Automation Namespace. But then I am lost how to really expand the variable.
The entry written into the logfile should look like this:
This is a text and I want to expand C:\temp\modules in my c# LogWriter class
Of course I know I can do this in my script using
$Log.AddInfo(($ExecutionContext.InvokeCommand.ExpandString($test)))
But this is nasty because it looks ugly and if I forget to add this statement no expansion is done.
So I thought of retrieving the current Runspace in my c# class and do the ExpandString-Command there to get the expanded variable but I fail.
This is beyond my knowledge.
Anyone here to tell my if this is possible? I already think of some other tasks where to use this so please do not start a flame war about if this makes sense or not.
Rgds
Jan
How can the value for $ModulesPath be known outside of your script?
If you want it to be expanded in C#, then you have to send it, may be as a second Parameter to AddInfo like:
$Log.AddInfo($test, $ModulesPath)
Now it's known and the replacement could be done by:
string sNew = sTest.Replace("$ModulesPath", sModulesPath);
where sTest and sModulesPath are the parameters.
not sure if this is what you're asking about, but please try using double quotes on the $test string:
$test = "This is a text and I want to expand $ModulesPath in my c# LogWriter class"
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.