A composite format string in conjunction with DataTable.Select() - c#

I've got an array with three elements
string[] cat = new string[3] { "XBox360", "PS3", "Wii" };
then my I basically compare the array agianst a DataTable and do some manipulation under certain conditions. The code that (I didn't write) performs match is this:
drResults = dtResults.Select(String.Format("Cat = '{0}' AND Cat_Entries = '{1}'", category, cat[i]));
The category (Cat) varialble contains a category numbers and Cat_Entries the elements of the cat array. And so in the code I perform operations if the drResult.Lenght > 0.
What I don't understand is what does the code inside Format() do? I'm looking at Microsoft's definition but what throws me off is the "AND". Also are the numbers between curly brackets {} like a sequential index designator that tell the runtime that the category element repalces Zero, and cat[i] replaces One?
All this is of course inside a loop and other code but I don't think it really adds to the question so I left it out.

The Select method takes a piece of SQL and returns rows that match. In this case you are looking for a row where Cat field = '<category>' AND the Cat_Entries field = '<cat[i]>'
The Format function is a better way of creating the string than doing
"Cat = '" + category + "' AND Cat_Entries = '" + cat[i] + '" as the latter is harder to read and is probably slower due to having to create several interim strings.
The {0} and {1} are just place holders representing the variables that you provide, ie.
category and cat[i]. You can reuse each as many times as you like and in any order,.e.g. it would be valid (albeit stupid) to have
String.Format("Cat_Entries = '{1}' AND Cat = '{0}' AND Cat = '{0}'", category, cat[i])

Related

Add comma in string if boolean is false

I have 3 booleans:
Boat, Plane, Car
And 3 strings:
ReloadBoat, ReloadPlane, ReloadCar
Depending on these booleans, if false, I need to add commas between the strings.
string errorMessage = (Boat? "" : " " + ReloadBoat) + (Plane? "" : (errMessage) + ReloadPlane) + (Car? "" : ", " + ReloadCar);
For the above, the issue I am getting is, if both Boat and Plane are true, I am getting the errorMessage as ", ReloadCar".
I want it to be "ReloadCar" only.
Any idea on how to do this?
Breaking it out makes the code more readable and maintainable. It'll get really hard work to use your bools in the manner you have there. Instead I recommend you put the commas on your error messages as a matter of routine. Concatenate them together and remove any trailing commas:
string err="";
if(boatNeedsReload)
err+="ReloadBoatErrorMessageWithComma, ";
if(planeNeedsReload)
err+="ReloadPlaneErrorMessageWithComma, ";
if(carNeedsReload)
err+="ReloadCarErrorMessageWithoutComma";
err = err.TrimEnd(new[]{' ',','});
So the method is:
Put punctuation between all your elements regardless
Trim off trailing redundant punctuation as the last operation
I didn't put any punctuation after ReloadCar because as the last item, it isn't strictly necessary. If this were extended in future to add another item at the end you'd have to remember to punctuate ReloadCar. You might thus wish to consider punctuating car right now and not have to remember to do it next time
If you use a stringbuilder you can interrogate the length and knock 2 off it if needs be:
StringBuilder err=new StringBuilder();
if(boat)
err.Append("ReloadBoat, ");
if(plane)
err.Append("ReloadPlane, ");
if(car)
err.Append("ReloadCar, ");
if(err.Length>0);
err.Length-=2;
this time I did punctuate reloadcar because this method wouldn't work properly without it
Don't try to do too much on one line in your code; you'll reach a point where it needs modifying in a months time and it'll take longer to work out how it works and how to extend it than just breaking it out to something readable and hence maintainable
As an example, this does the same as the first code block, but it's a bit "what the..?"
string err = (
(boatNeedsReload ? "ReloadBoatErrorMessageWithComma, ":"")+
(planeNeedsReload ? "ReloadPlaneErrorMessageWithComma, ":"")+
(carNeedsReload ? "ReloadCarErrorMessageWithoutComma":""))
.TrimEnd(new[]{' ',','});
Falco makes a good point, that you should strive to make your Boolean variables have a name that declares a truth, like "isTooYoung" or "boatNeedsReload". Make your Boolean have a positive spirit, as it starts to get confusing if you write if(boatDoesntNeedReload==false). Note also that classic advice is to not compare a Boolean with another Boolean to realise a Boolean, but consider that comparing with false can make code more readable than using ! to invert a truth
I would create a list of strings with errors and appended to it based on the bools and string join them with a comma or whatever you want.
var boatErrorMessage = "boatErrorMessage";
var planeErrorMessage = "planeErrorMessage ";
var carErrorMessage = "carErrorMessage";
var isBoat = true;
var isPlane = false;
var isCar = true;
var errorMessageList = new List<string>();
if (isBoat)
errorMessageList.Add(boatErrorMessage);
if (isPlane)
errorMessageList.Add(planeErrorMessage);
if (isCar)
errorMessageList.Add(carErrorMessage);
Console.WriteLine(string.Join(", ", errorMessageList));
Output: boatErrorMessage, carErrorMessage

What is the difference between {0} and +?

Is there any difference between the use of {0} and + as they both are doing the same work of printing the length on the screen:
Console.WriteLine("Length={0}", length);
Console.WriteLine("Length=" + length);
In your trivial example there's no difference. But there are very good reasons to prefer the formatted ({0}) option: it makes localization of international software much, much easier, and it makes editing your existing strings by third parties much easier.
Imagine for example you're writing a compiler that produces this error message:
"Cannot implicitly convert type 'int' to 'short'"
Do you really want to write the code
Console.WriteLine("Cannot implicitly convert type '" + sourceType + "' to '" + targetType + "'");
? Good heavens no. You want to put this string into a resource:
"Cannot implicitly convert type '{0}' to '{1}'"
and then write
Console.WriteLine(FormatError(Resources.NoImplicitConversion, sourceType, targetType));
Because then you have the freedom to decide that you want to change that to:
"Cannot implicitly convert from an expression of type '{0}' to the type '{1}'"
Or
"Conversion to '{1}' is not legal with a source expression of type '{0}'"
These choices can be made later, by English majors, without requiring changes to the code.
You can also translate those resources into other languages, again without changing the code.
Start always using formatting strings now; when you need to write localizable software that uses string resources properly, you'll already be in the habit.
The second line will create a string and print the string out.
The first line will use composite formatting, like string.Format.
Here are some good reasons to use composite formatting.
There is a difference.
ex:
Console.WriteLine("the length is {0} which is the length", length);
Console.WriteLine("the length is "+length+" which is the length");
+ concatenates two strings, {0} is a placeholder for a string to be inserted.
{n} is a placeholder which can be used with multiple options. where n is a number
In your example it would make a difference and the end result would be same that is concatenation of two string. However in something like
var firstName = "babba";
var lastName ="abba";
var dataOfBirth = new Date();
Console
.Write(" Person First Name : {0} | Last Name {1} }| Last Login : {2:d/M/yyyy HH:mm:ss}",
firstName,
secondName,
dateOfBirth);
it provides a easy to read interface with easy formatting
{n} where n >= 0 allows you to substitute values in order of occurrence in the string.
string demo = "demo", example = "example";
Console.WriteLine("This is a {0} string used as an {1}", demo, example);
+ allows you to concatenate two or more strings together.
Console.WriteLine("This is a " + demo + " string used as an " + example);

Outlook Find/Restrict with contain

is there anyway I can use Find or Restrict with something like outlookfield.contains(mystring)?
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._items.restrict%28v=office.14%29.aspx
According to the documentation you linked to, no there is no way to do it.
Additional Notes
If you are trying to use the Find or Restrict methods with
user-defined fields, the fields must be defined in the folder,
otherwise an error will occur. There is no way to perform a "contains"
operation. For example, you cannot use Find or Restrict to search for
items that have a particular word in the Subject field. Instead, you
can use the AdvancedSearch method, or you can loop through all of the
items in the folder and use the InStr function to perform a search
within a field. You can use the Restrict method to search for items
that begin within a certain range of characters. For example, to
search for all contacts with a last name beginning with the letter M,
use this filter:
sFilter = "[LastName] > 'LZZZ' And [LastName] < 'N'"
It isn't clear from your question exactly what you are trying to do so to give some more context I am trying to count all the emails that have a subject containing a certain string (I've called it mystring to match your example).
Here is the code I started with:
string mystring = "Such String";
int count = inboxFolder.Items.Restrict("[Subject] = " + mystring).Count;
Debug.WriteLine("{0} email(s) contain '{1}'", count, mystring);
This would work so long as the subject of the email was an exact match to mystring which isn't good enough, I needed it to count if the string was contained anywhere in the subject.
I tried Axel Kemper's answer of adding * symbols as a wildcard but it didn't work for me.
Rather than use the AdvancedSeach method (its rather cryptic documentation here) I opted to perform a loop through each item and check manually if it contained the string of interest:
string mystring = "Such String";
int count = 0;
foreach (var item in inboxFolder.Items)
{
if (item is Outlook.MailItem)
{
Outlook.MailItem mailItem = item as Outlook.MailItem;
if (mailItem.Subject != null && mailItem.Subject.Contains(mystring))
{
count++;
}
}
}
Debug.WriteLine("{0} email(s) contain '{1}'", count, mystring);
I've left the code unrefactored to ease readability and understanding but this can also be made into a one liner LINQ expression:
string mystring = "Such String";
int count = inboxFolder.Items.OfType<Outlook.MailItem>().Count(mailItem => mailItem.Subject != null && mailItem.Subject.Contains(mystring));
Debug.WriteLine("{0} email(s) contain '{1}'", count, mystring);
Output from both:
42 email(s) contain 'Such String'
You can specify fields in squared brackets like shown in the following snippets:
Set contact = objContacts.Items.Find("[Email1Address]=" & Chr(34) & .SenderEmailAddress & Chr(34))
Set contact = objContacts.Items.Find("[FileAs] = ""Smith, Jeff"" and [FirstName] = ""Jeff""")
The fieldnames are described in the MSDN documentation or can be inspected using the VBA object catalog viewer.
To implement Contains, you can use * as wildcard before and after the string you are looking for (eg "*myString*"). To search the field for a literal *, you have to use ~*.

String Format with undefined number of characters c#

So I'm working on formatting a string and I need to line it up in a table, but this string has an undetermined number of characters. Is there anyway to have the string be in the same spot for each column? so far I have:
ostring += "Notes\t\t"
+ " : "
+ employees[number].Notes
+ "\t\t"
+ employees[number].FirstNotes
+ "\t\t"
+ employees[number].SecondNotes;
I use a similar fashion on the other rows, but they have a pre-determined number of digits, this however doesn't so I can't use the string modifiers like I would like.
Any ideas on what I need to do?
You can use String.PadRight() to force the string to a specific size, rather than using tabs.
When you are using String.Format item format has following syntax:
{ index[,alignment][ :formatString] }
Thus you can specify alignment which indicates the total length of the field into which the argument is inserted and whether it is right-aligned (a positive integer) or left-aligned (a negative integer).
Also it's better to use StringBuilder to build strings:
var builder = new StringBuilder();
var employee = employees[number];
builder.AppendFormat("Notes {0,20} {1,10} {2,15}",
employee.Notes, employee.FirstNotes, employee.SecondNotes);
You would first have to loop over every entry to find the largest one so you know hoe wide to make the columns, something like:
var notesWidth = employees.Max(Notes.Length);
var firstNotesWidth = employees.Max(FirstNotes.Length);
// etc...
Then you can pad the columns to the correct width:
var output = new StringBuilder();
foreach(var employee in employees)
{
output.Append(employee.Notes.PadRight(notesWidth+1));
output.Append(employee.FirstNotes.PadRight(firstNotesWidth+1));
// etc...
}
And please don't do a lot of string "adding" ("1" + "2" + "3" + ...) in a loop. Use a StringBuilder instead. It is much more efficient.

Comma Separated text file to Generic List

Having a bit of trouble with converting a comma separated text file to a generic list. I have a class (called "Customers") defined with the following attributes:
Name (string)
City (string)
Balance (double)
CardNumber (int)
The values will be stored in a text file in this format: Name,City, Balance, CarNumber e.g. John,Memphis,10,200789. There will be multiple lines of this. What I want to do is have each line be placed in a list item when the user clicks a button.
I've worked out I can break each line up using the .Split() method, but have no idea how to make the correct value go into the correct attribute of the list. (Please note: I know how to use get/set properties, and I am not allowed to use LINQ to solve the problem).
Any help appreciated, as I am only learning and have been working on this for a for while with no luck. Thanks
EDIT:
Sorry, it appears I'm not making myself clear. I know how to use .add.
If I have two lines in the text file:
A,B,1,2 and
C,D,3,4
What I don't know how to do is make the name "field" in the list item in position 0 equal "A", and the name "field" in the item in position 1 equal "C" and so on.
Sorry for the poor use of terminology, I'm only learning. Hope you understand what I'm asking (I'm sure it's really easy to do once you know)
The result of string.Split will give you an array of strings:
string[] lineValues = line.Split(',');
You can access values in an array by index:
string name = lineValues[0];
string city = lineValues[1];
You can convert strings to double or int using their respective Parse methods:
double balance = double.Parse(lineValues[2]);
int cardNumber = int.Parse(lineValues[3]);
You can instantiate the class and assign to it very simply:
Customer customerForCurrentLine = new Customer()
{
Name = name,
City = city,
Balance = balance,
CardNumber = cardNumber,
};
Simply loop over the lines, instantiate a Customer for that line, and add it to a variable you've created of the type List<Customer>
If you want your program to be bulletproof, you're going to have to do a lot of checking to skip over lines that don't have enough values, or that would fail to parse to the correct number type. For example, check lineValues.Length == 4 and use int.TryParse(...) and double.TryParse(...).
Read a file and split its text based on newline character. Then for total line count run a loop that will split based on comma and create a new object and insert values in its properties and add that object to a list.
This way
List<Customers> lst = new List<Customers>();
string[] str = System.IO.File.ReadAllText(#"C:\CutomersFile.txt")
.Split(new string[] { Environment.NewLine },
StringSplitOptions.None);
for (int i = 0; i < str.Length; i++)
{
string[] s = str[i].Split(',');
Customers c = new Customers();
c.Name = s[0];
c.City = s[1];
c.Balance = Convert.ToDouble(s[2]);
c.CardNumber = Convert.ToInt32(s[3]);
lst.Add(c);
}
BTW class name should be Customer and not Customers
Split() generates an array of strings in the order they appeared in the source string. Thus, if your name field is the first column in the CSV file, it will always be the first index in the array.
someCustomer.Name = splitResult[0];
And so on. You'll also need to investigate String.TryParse for your class's numerically typed properties.

Categories

Resources