Lets say your writing a plug-in for an application "SomeApp.exe" at the following directory:
"D:\Projects\Smed\win32_vs90\Debug\SomeApp.exe"
Under "Build" tab set
"Output path:" by using the "Browse" button browse to "D:\Projects\Smed\win32_vs90\Debug\"
Under "Debug" tab set
"Start external program:" to "D:\Projects\Smed\win32_vs90\Debug\SomeApp.exe"
"Working directory" to "D:\Projects\Smed\win32_vs90\Debug\"
Under "Reference Paths" tab
Add "D:\Projects\Smed\win32_vs90\Debug\" to the reference paths
December 16, 2009
December 15, 2009
GetRelativePath Helper
public static class FileSystemInfoExtender
{
public static string GetPathRelativeTo(this FileSystemInfo file, string path)
{
string fullPath = Path.GetFullPath(path);
string res = string.Empty;
if (file.FullName.StartsWith(fullPath))
{
res = file.FullName.Substring(fullPath.Length);
}
res = res.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
string sep = Path.DirectorySeparatorChar.ToString();
if (res.StartsWith(sep))
{
res = res.Substring(1);
}
return res;
}
}
and some tests
FileInfo file = new FileInfo(@"D:\Projects\smeg\src\blah\xxxx\whistle\stop\Carbuncle.cs"); string relPath = file.GetPathRelativeTo(@"D:\Projects\smeg\src"); Debug.Assert(relPath.Equals(@"blah\xxxx\whistle\stop\Carbuncle.cs", StringComparison.OrdinalIgnoreCase)); relPath = file.GetPathRelativeTo(@"D:/Projects/smeg/src"); Debug.Assert(relPath.Equals(@"blah\xxxx\whistle\stop\Carbuncle.cs", StringComparison.OrdinalIgnoreCase)); relPath = file.GetPathRelativeTo(@"D:\Projects\smeg\src\"); Debug.Assert(relPath.Equals(@"blah\xxxx\whistle\stop\Carbuncle.cs", StringComparison.OrdinalIgnoreCase));
November 26, 2009
Accessing Command Line Arguments In WPF
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs sea)
{
CommandLine.Instance.SetArguments(sea.Args);
base.OnStartup(sea);
}
}
public class CommandLine
{
private CommandLine()
{}
private static readonly CommandLine instance = new CommandLine();
public static CommandLine Instance
{
get { return instance; }
}
public IEnumerable Arguments
{
get { return args; }
}
public void SetArguments(string[] args)
{
this.args = args ?? new string[0];
}
private string[] args = new string[0];
}
then to use private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (string arg in CommandLine.Instance.Arguments)
{
if (arg.ToUpper() == "/C")
{
if (System.Windows.Forms.Clipboard.ContainsText())
{
tbCode.Text = System.Windows.Forms.Clipboard.GetText();
}
}
}
}
Doh!Even easier:
string[] arguments = Environment.GetCommandLineArgs();When processing command line args using Environment.CommandLineArgs(), found that the system automatically matches " in an argument. So if you have a path that contains a spaces, as long as that path is wrapped with " marks, the path will not be parsed into multiple arguments but rather appear as a single argument. eg.:
-myArg:C:\Program Files\MyProgram\Something.exe
will get parsed as multiple arguments:
- -myArg:C:\Program
- Files\MyProgram\Something.exe
-myArg:"C:\Program Files\MyProgram\Something.exe"
will get parsed as a single argument:
- -myArg:C:\Program Files\MyProgram\Something.exe
Have also noticed that carriage return line feeds can get sucked into a command line argument. Perhaps a "Trim()" should be applied to each argument string before it is processed to be sure this whitespace is removed. Here is a sample command line parser:
internal class CommandLineParser
{
public string Drive { get; set; }
public string TrueCryptFile { get; set; }
public string KeyFile { get; set; }
const string DrivePrefix = "-D";
const string TrueCryptFilePrefix = "-T";
const string KeyFilePrefix = "-K";
public void CommandLineArgs(string[] args)
{
//string[] args = Environment.GetCommandLineArgs();
Debug.WriteLine("Args:" + string.Join(",", args));
int ix = 0;
foreach (string arg in args)
{
Debug.WriteLine("arg[" + ix++.ToString() + "]=\'" + arg + "\'");
}
foreach (string rawArg in args)
{
// Get rid of whitespace chars at the beginning and end
string arg = rawArg.Trim();
if (arg.Length < 2)
continue;
string argument = (arg[0] == '/') ? "-" + arg.Substring(1) : arg;
int end = argument.IndexOf(':');
if ((end == -1) && ((end + 1) >= argument.Length))
continue;
if (argument.ToUpper().StartsWith(DrivePrefix))
{
Drive = argument.Substring(end + 1).Substring(0, 1) + ":";
}
else if (argument.ToUpper().StartsWith(TrueCryptFilePrefix))
{
TrueCryptFile = argument.Substring(end + 1);
}
else if (argument.ToUpper().StartsWith(KeyFilePrefix))
{
KeyFile = argument.Substring(end + 1);
}
}
Debug.WriteLine("Processed command line args:");
Debug.WriteLine("Drive=\"" + Drive + "\"");
Debug.WriteLine("TrueCryptFile=\"" + TrueCryptFile + "\"");
Debug.WriteLine("KeyFile=\"" + KeyFile + "\"");
}
}
// and tester (not really finished)
class CommandLineParserTester
{
public void TestCommandLineParser()
{
CommandLineParser clp = new CommandLineParser();
clp.CommandLineArgs(new string[] {
@"-D:M",
@"-T:F:/Temp/truecrypt.tc",
@"-K:F:/Temp/truecrypt.keyfile" });
Assert(clp.Drive == "M:");
Assert(clp.TrueCryptFile == @"F:/Temp/truecrypt.tc");
Assert(clp.KeyFile == @"F:/Temp/truecrypt.keyfile");
}
}
Labels:
Command Line Arguments,
Program Arguments
November 19, 2009
Debugger/Editor Attributes
DebuggerDisplay - Use it to specify how a class or struct should be displayed in the debugger when the cursor hover over the item
EditorBrowsable - Use this 'EditorBrowsable' property to restrict intellisense/visual studio visibility of a property
DefaultValue - Then there is the 'DefaultValue' property that sets the default value of a C# class property. Used by visual designers, etc
[DebuggerDisplay("Count = {count}")]
class blahblahblah ...
DebuggerStepThrough - Instructs the debugger to step through that marked property or attribute, and not into it: [DebuggerStepThrough]
public int Key
{
[System.Diagnostics.DebuggerStepThrough]
get { return key; }
[System.Diagnostics.DebuggerStepThrough]
set { key = value; }
}
DebuggerBrowsable - Determines if and how a field or property is displayed in the debugger variable windows. [DebuggerBrowsable(DebuggerBrowsableState.Never)] private int key;see also DebuggerDisplay and DebuggerBrowsable – Two Debugger Attributes you should know
EditorBrowsable - Use this 'EditorBrowsable' property to restrict intellisense/visual studio visibility of a property
[EditorBrowsable(EditorBrowsableState.Never)] int MyProperty ...
DefaultValue - Then there is the 'DefaultValue' property that sets the default value of a C# class property. Used by visual designers, etc
[DefaultValue(42)]
public int MyProperty { get; set; }
Sample Linq
In order to use Linq in the following ways a reference to the 'System.Core' assembly is required. The namespace is 'System.Linq'.
Useful Links
In some cases when an IEnumerable returns no entries at all the Linq operator will throw an exception using the "OrDefault" option will circumvent this problem. In the case that there are no entries returned from an XXXOrDefault operator, Linq will return the default value for the generic parameter. In the case of a reference type this will be null. For a value type it will return the default value for that value type.
SelectMany() - SelectMany flatten nested enumerables, see here for a good example
Linq Set operators:
Useful Links
- 101 Linq samples - Good concise explanation of all Linq methods
- Introducing Linq - Good explanation of Linq (How and Why)
private Smeg FindSmeg(Project project, string smegName)
{
SpellRoot spellRoot = SpellRoot.Get(project);
SmegCollection smegs = spellRoot.SmegCollection;
// Note that the 'smegVar' is an IEnumerable
var smegVar = from bh in smegs
where bh.Name.Equals(smegName,
StringComparison.OrdinalIgnoreCase)
select bh;
Smeg smeg = smegVar.FirstOrDefault();
return smeg;
}
private Smeg FindSmeg2(Project project, string smegName)
{
SpellRoot spellRoot = SpellRoot.Get(project);
SmegCollection smegs = spellRoot.SmegCollection;
// Declaring a Func type lambda expression
// A good way to learn how to form correct lambda expressions
Func smegSelector =
bh => bh.Name.Equals(smegName, StringComparison.OrdinalIgnoreCase);
Smeg smeg = smegs.FirstOrDefault(smegSelector);
return smeg;
}
private Smeg FindSmeg3(Project project, string smegName)
{
SpellRoot spellRoot = SpellRoot.Get(project);
SmegCollection smegs = spellRoot.SmegCollection;
// Inline lambda expression
Smeg smeg = smegs.FirstOrDefault(
bh => bh.Name.Equals(smegName, StringComparison.OrdinalIgnoreCase));
return smeg;
}
Simple examples
Count() - Get count of items in an enumerationIEnumerableToArray() - enumeration to an arraysmegs = ... int count = smegs.Count();
IEnumerableToList() - enumeration to a listsmegs = ... Smeg smegArr = smegs.ToArray();
IEnumerableWhere() - This is a general purpose filter, the function in the Where clause performs the filteringsmegs = ... IList smegList = smegs.ToList();
File.ReadLines( @"D:\Users\ukrb\Docs\SpcPressures.txt" ).
Where(li => li.Contains(" PRESSURE")). // Filter out any line NOT containing the specified string (" PRESSURE")
Dump();
Select() - Allows you to Select portions of/Convert each enumerated item to an item of another type (not by casting but by extraction or conversion). Anonymous types can be used for conversion to simple intermediate types// This parses a file of data where each line contains a number of samples, their average, maximum, minimum, etc.
File.ReadLines( @"D:\Users\ukrb\Docs\PRESSURE 214289.DAT" ).
Select(li => ParseLine(li)). // ParseLine is a function returning a specific class type instance
Select(pe => pe.ToV10Form()). // Now convert it to another more readable string of only data that is interesting
Dump();
Single() - Returns the single matching element in the enumeration, if there is not exactly one match an 'InvalidOperationException' exception is thrown.IEnumerableFirst() - first element in an enumeration, be careful an exception is thrown if the enumeration is empty! If your enumeration maybe empty use FirstOrDefaultsmegs = ... Smeg first = smegs.Single();
IEnumerableFirstOrDefault() - first element in an enumeration, and when it is empty, the default value of the enumerated type (which is always null for a reference type)smegs = ... Smeg first = smegs.First();
IEnumerableLast() - last element in an enumeration, be careful an exception is thrown if the enumeration is empty!smegs = ... Smeg first = smegs.FirstOrDefault();
IEnumerableSkip() - skip the first n elements in an enumeration and return what is left, be careful an exception is thrown if the enumeration has less than n itemssmegs = ... Smeg last = smegs.Last();
string[] allArgs = Environment.GetCommandLineArgs(); IEnumerable<string> args = allArgs.Skip(1); // First argument is the exe pathOfType() - extract from an enumeration all objects of the given type. Safe way of converting an enumeration of one type to another, it uses the 'is' operator. An excellent way to filter out null objects in a sequence. There is the "Cast<>()" operator but the trouble with this is that it will throw an exception if one of the objects of the enumeration is not of the given type so only use that when you know that all the elements of the enumeration will cast to the new type
IEnumerableCast() - Casts all items in the enumeration to the given type. When an item can not be cast to the new type then an exception is thrown. Useful to convert old style enumerables of known types. For example:smegs = ... int numSquares = smegs.OfType ().Count();
StringCollection sc = this.settingsService.GetProperty
<StringCollection>(SourceDirectoriesSetting) ?? new StringCollection();
if (sc.Count > 0)
{
// Cast the string collection 'sc' entries to strings
ObservableCollection<string> oc = new ObservableCollection<string>(sc.Cast<string>());
...
}
Using the XXXOrDefault (First, Single, Last, ElementAt) option:In some cases when an IEnumerable returns no entries at all the Linq operator will throw an exception using the "OrDefault" option will circumvent this problem. In the case that there are no entries returned from an XXXOrDefault operator, Linq will return the default value for the generic parameter. In the case of a reference type this will be null. For a value type it will return the default value for that value type.
SelectMany() - SelectMany flatten nested enumerables, see here for a good example
Linq Set operators:
- Union - Simply appends one IEnumerable to another
- Intersect - Finds items common to 2 IEnumerables
- Except - Subtracts one IEnumerable from another
- Distinct - Removes duplicate items from a single IEnumerable (Operates on a single IEnumerable!)
November 12, 2009
Math.Round
Math.Round() can be made to work in the conventional manner for rounding numbers using the 'MidpointRounding.AwayFromZero' argument
eg
// Round to 2 decimal places.
public double RoundUpTo2Dp(double arg)
{
// so xx.xx5 becomes xx.x(x+1)0 where x is a digit in a double number
return Math.Round(arg, 2, MidpointRounding.AwayFromZero);
}
October 7, 2009
@ Character In Identifiers
The c# language specification says
The "@" character is allowed as a prefix to enable keywords to be used as identifiers..
Hence the following is possible:
public class Case {};
public class XXXX
{
private Case m_Case;
public XXXX(Case @case)
{
m_Case = @case;
}
}
Useful for events:var @event = new Event(...);
Subscribe to:
Posts (Atom)