Given this powershell code:
$drivers = New-Object 'System.Collections.Generic.Dictionary[String,String]'
$drivers.Add("nitrous","vx")
$drivers.Add("directx","vd")
$drivers.Add("openGL","vo")
Is it possible to initialize this dictionary directly without having to call the Add method. Like .NET allows you to do?
Something like this?
$foo = New-Object 'System.Collections.Generic.Dictionary[String,String]'{{"a","Alley"},{"b" "bat"}}
[not sure what type of syntax this would involve]
No. The initialization syntax for Dictionary<TKey,TValue> is C# syntax candy. Powershell has its own initializer syntax support for System.Collections.HashTable (#{}):
$drivers = #{"nitrous"="vx"; "directx"="vd"; "openGL"="vo"};
For [probably] nearly all cases it will work just as well as Dictionary<TKey,TValue>. If you really need Dictionary<TKey,TValue> for some reason, you could make a function that takes a HashTable and iterates through the keys and values to add them to a new Dictionary<TKey,TValue>.
The C# initializer syntax isn't exactly "direct" anyway. The compiler generates calls to Add() from it.
For those who like to really use Dictionary.
In my case I had to use another c# dll which has a dictionary as parameter:
New-Object "System.Collections.Generic.Dictionary[String,String]"
This was probably not possible back in 2011
$d = [System.Collections.Generic.Dictionary[String,Object]]::new()
#works now.
$d.Add('keyvalue', #{x=1; y='abc'})
#Evaluate dictionary
$d
<# outputs
Key Value
--- -----
keyvalue {y, x}
#>
#evalueate contains key:
$d.Keys.Contains('keyvalue')
<# outputs
True
#>
# Evaluate the value using the key
$d['keyvalue']
<# outputs
Name Value
---- -----
y abc
x 1
#>
#Evaluate the y property of the object
$d['keyvalue'].y
<# outputs
abc
#>
# Evaluate the x property of the object
$d['keyvalue'].x
<# outputs
1
#>
Related
I want to do the equivalent of the following VB in c#
Function([class]) "hello"
This would be the same as this in c#
class=>"hello"
The problem is that the word class is a key word in the language. But I want to use it as a variable name. In the VB example you can use the [] brackets to 'escape' that key word and allow it to be used as a variable name.
Is there a way to do this in C# ?
You need to add # to variable names:
#class
But it is a very bad practice. Every time you name your variable as a keyword a kitten dies :)
Use # for reserved words:
#class=>"hello"
You can prefix any keyword with a #.
But I don't think it's a recommended practice, and code analysis complains about it for sure.
I'm now writing C# grammar using Antlr 3 based on this grammar file.
But, I found some definitions I can't understand.
NUMBER:
Decimal_digits INTEGER_TYPE_SUFFIX? ;
// For the rare case where 0.ToString() etc is used.
GooBall
#after
{
CommonToken int_literal = new CommonToken(NUMBER, $dil.text);
CommonToken dot = new CommonToken(DOT, ".");
CommonToken iden = new CommonToken(IDENTIFIER, $s.text);
Emit(int_literal);
Emit(dot);
Emit(iden);
Console.Error.WriteLine("\tFound GooBall {0}", $text);
}
:
dil = Decimal_integer_literal d = '.' s=GooBallIdentifier
;
fragment GooBallIdentifier
: IdentifierStart IdentifierPart* ;
The above fragments contain the definition of 'GooBall'.
I have some questions about this definition.
Why is GooBall needed?
Why does this grammar define lexer rules to parse '0.ToString()' instead of parser rules?
It's because that's a valid expression that's not handled by any of the other rules - I guess you'd call it something like an anonymous object, for lack of a better term. Similar to "hello world".ToUpper(). Normally method calls are only valid on variable identifiers or return values ala GetThing().Method(), or otherwise bare.
Sorry. I found the reason from the official FAQ pages.
Now if you want to add '..' range operator so 1..10 makes sense, ANTLR has trouble distinguishing 1. (start of the range) from 1. the float without backtracking. So, match '1..' in NUM_FLOAT and just emit two non-float tokens:
I use the following code and I not understand the following :
1. why I don't see the definition string name inside the txt file or the for statement since this is inside the tag
2.if I want to see it do I need to use different tag?
<#
string name = "Sop";
#>
Hello there ,<#=name #>
<#
for (int i = 0; i < 5; i++)
{
#>
Hi!
<#
}
#>
The output is
Hello there ,Sop
Hi!
Hi!
Hi!
Hi!
Hi!
Your code in between evaluation tags <# #> so that it will evaluate and run, but it won't be part of the output. If you wish to generate code, don't use the tags. More info about T4 templates as always available on MSDN. Especially this link pointing to MSDN is quite thorough about code generating from xml file storing definitions.
in C++, one can use this expression:
#define IDENTIFIER NAME
eg. #define MY_NAME "Gideon"
Is this similarly possible in C#?
No. #define can only be used to define flags to be tested with #if (and then only at the start of a file).
Use a constant string instead:
const string MY_NAME = "Gideon";
Those are completely different things. In C++ it basically replaces the string MY_NAME with expression assigned to it "Gideon".
The same happens in C#, in case of canstant expression, but in C++ you can define complete macros(functions) to MY_NAME in order to make them run, which is not possible in C#
I am not saying you should do it or that it is going to work as you expect, but there is nothing stopping you from trying to use a C preprocessor (e.g. GNU cpp) on your code.
I run the command (Get-Location), and it returns the current location of a file.
Example: c:\folder1\folder2\folder3\XXX\folder4\folder5
Firstly, from the above, I want to get the value of XXX and let it equal to a variable. How can I do this?
Secondly, I want to get the value of c:\folder1\folder2\folder3\XXX\folder4\ and let it equal to a variable. How can I do this?
I have used the placeholders folder1, folder2, etc. for illustration. These are dynamic.
To answer your second question first: to get the parent to the full path, use Split-Path:
$var = Split-Path -parent "c:\folder1\folder2\folder3\XXX\folder4\folder5"
For your other question, this function will split all the elements of your path and return them into an array:
function Split-Paths($pth)
{
while($pth)
{
Split-Path -leaf $pth
$pth = Split-Path -parent $pth
}
}
You can then grab the 5th element like this:
$xxx = (Split-Paths "c:\folder1\folder2\folder3\XXX\folder4\folder5")[-5]
Note that the function returns the elements in "reverse" order, so you use a negative index to index from the end of the array.
Some of these answers are pretty close, but everyone is forgetting their shell-fu.
$FirstAnswer = (Get-Item ..\..).Name
$SecondAnswer = (Get-Item ..).FullName
To get the path into a variable, you can do something like this:
$a = (Get-Location).Path
Then, if you want to set the value of the 'XXX' part of your path to a variable, you can use the split() function:
$x = $a.split('\')[4]
You could do this with a regular expression:
PS> $path = 'c:\folder1\folder2\folder3\XXX\folder4\folder5'
PS> $path -match 'c:\\([^\\]+)\\([^\\]+)\\([^\\]+)\\([^\\]+)'
True
PS> $matches
Name Value
---- -----
4 XXX
3 folder3
2 folder2
1 folder1
0 c:\folder1\folder2\folder3\XXX
You can use regular expressions:
$rawtext = "If it interests you, my e-mail address is tobias#powershell.com."
# Simple pattern recognition:
$rawtext -match "your regular expression"
*True*
# Reading data matching the pattern from raw text:
$matches
$matches returns the result.
For more information, check Chapter 13. Text and Regular Expressions (requires registration).