Convert VBA select case to C# - c#

Select Case True
Case Not A.Name Is Nothing
Set Name = A.Name
Case Not A.Age Is Nothing
Set Age = A.Age
Case Not A.School Is Nothing
Set School = A.School
End Select
In VB Select Case True is allowed to use. But for C# it gives an error. How can I convert this VB code to C# ?

There is no direct analog in C# because C# case labels must be constant expressions. Select Case True is an unusual construct that serves as an alternative to if-else constructs.
I suggest replacing it with the far more common pattern:
if (A.Name != null)
Name = A.Name;
if (A.Age != null)
Age = A.Age;
// ... etc

Using switch case in c# is some different. I think this example can be able to useful to you.
using System;
using System.Collections.Generic;
using System.Linq;
public class Example
{
public static void Main()
{
var values = new List<object>();
for (int ctr = 0; ctr <= 7; ctr++) {
if (ctr == 2)
values.Add(DiceLibrary.Roll2());
else if (ctr == 4)
values.Add(DiceLibrary.Pass());
else
values.Add(DiceLibrary.Roll());
}
Console.WriteLine($"The sum of { values.Count } die is { DiceLibrary.DiceSum(values) }");
}
}
public static class DiceLibrary
{
// Random number generator to simulate dice rolls.
static Random rnd = new Random();
// Roll a single die.
public static int Roll()
{
return rnd.Next(1, 7);
}
// Roll two dice.
public static List<object> Roll2()
{
var rolls = new List<object>();
rolls.Add(Roll());
rolls.Add(Roll());
return rolls;
}
// Calculate the sum of n dice rolls.
public static int DiceSum(IEnumerable<object> values)
{
var sum = 0;
foreach (var item in values)
{
switch (item)
{
// A single zero value.
case 0:
break;
// A single value.
case int val:
sum += val;
break;
// A non-empty collection.
case IEnumerable<object> subList when subList.Any():
sum += DiceSum(subList);
break;
// An empty collection.
case IEnumerable<object> subList:
break;
// A null reference.
case null:
break;
// A value that is neither an integer nor a collection.
default:
throw new InvalidOperationException("unknown item type");
}
}
return sum;
}
public static object Pass()
{
if (rnd.Next(0, 2) == 0)
return null;
else
return new List<object>();
}
}
You can give more information here about switch case

Your VBA code mimics an If-Then-ElseIf ... block, so how about:
if (A.Name != null)
{
Name = A.Name;
}
else if (A.Age != null)
{
Age = A.Age;
}
else if (A.School != null)
{
School = A.School;
}

Related

Compare Enums in if statement

I want to compare some enums on ifs statements here is what I mean but this isnt working. Basically I want to see if the injury is the same as the enum so if for example the injury is bleeding you need to bandage etc. If you need any other information please let me know.
static string injuries = GetInjuriesName(GetInjuries(closestPlayer));
EPedInjuries result;
if (Enum.TryParse(injuries, out result) && result == EPedInjuries.Overdose)
{
.....
}
else if (Enum.TryParse(injuries, out result) && result == EPedInjuries.GunShotWound)
{
....
}
....
public enum EPedInjuries
{
OpenFracture,
GunShotWound,
Fever,
BrokenLeg,
BrokenArm,
BrokenRib,
Overdose,
.....
}
public static EPedInjuries GetInjuries(Ped ped)
{
Ped = ped;
int num = API.Common.Random.Next(0, 101);
if (num >= 0 && num <= 37)
{
return EPedInjuries.Overdose;
}
if (num > 37 && num <= 55)
{
return EPedInjuries.GunShotWound;
}
if (num > 55 && num <= 72)
{
return EPedInjuries.CardiacArrest;
}
....
}
public static string GetInjuriesName(EPedInjuries injuries)
{
string result = string.Empty;
switch (injuries)
{
case EPedInjuries.Overdose:
result = "~r~Overdose";
break;
case EPedInjuries.GunShotWound:
result = "~r~Gunshot Wound";
break;
case EPedInjuries.CardiacArrest:
result = "~r~Cardiac Arrest";
break;
....
}
return result;
}
The GetInjuries method already returns the enum type you want to compare. As #Johnny Mopp points out, you are getting the enum, converting it to some string, only to try to convert it back to an enum
Just do
EPedInjuries result = GetInjuries(closestPlayer);
if (result == EPedInjuries.Overdose)
{
.....
}
else if (result == EPedInjuries.GunShotWound)
{
....
}
Your GetInjuriesName returns string which is not correct enum value and Enum.TryParse can't parse it and returns false:
var injuries = GetInjuriesName(EPedInjuries.Overdose);
Console.WriteLine(injuries); //prints "~r~Overdose"
Console.WriteLine(Enum.TryParse(injuries, out EPedInjuries result)); // prints "False"
Just introduce two fields/variables one for name and one for injury enum value:
EPedInjuries injury = GetInjuries(closestPlayer)
string injuryName = GetInjuriesName(injury);
And use the first one to handle the logic:
if(injury == EPedInjuries.Overdose)
{
....
}
.....
I believe you will receive strings from somewhere else so you want to convert that's why you have that GetInjuriesName method. For me, you should just switch on the strings you receive.
For the sake of fixing this code, you should remove the "~r~" from the strings so that it matches any enum type.
Also, enums can't be null so you will always get the first value which is the Default.
public static string GetInjuriesName(EPedInjuries injuries)
{
string result = string.Empty;
switch (injuries)
{
case EPedInjuries.Overdose:
result = "Overdose";
break;
case EPedInjuries.GunShotWound:
result = "Gunshot Wound";
break;
case EPedInjuries.CardiacArrest:
result = "Cardiac Arrest";
break;
}
return result;
}
Then the TryParse will work and produce a value contained inside the enum.

How to use an object from try in catch - c#

I want to use an object in catch block, which get me an exception in try block. I'm parsing some strings to int and need to catch the exception when it's impossible and see, what object was mistaken and in what line. Is that possible or not?
Some code dor example. Thanks.
static void Main(string[] args)
{
var result = Parse(new List<string>() { "3;5;7", "qwe;3;70" });
}
public static List<int[]> Parse(List<string> list)
{
try
{
return list.Select(str => str.Split(';'))
.Select(str => Tuple.Create(int.Parse(str[0]), int.Parse(str[1]), int.Parse(str[2])))
/// something happening
.ToList();
}
catch
{
//here in braces I want to know, which element was wrong
//"qwe" and whole line "qwe;3;70"
throw new FormatException($"Wrong line [{}]");
}
}
Declare the line and value item counters outside the try/catch block and increase them in the LINQ expression body:
public static List<int[]> Parse(List<string> list)
{
int line = 0;
int item = 0;
try
{
return list
.Select(str => {
line++;
item = 0;
return str
.Split(';')
.Select(i => { item++; return int.Parse(i); })
.ToArray();
})
.ToList();
}
catch
{
throw new FormatException($"Wrong line [{line}]; item [{item}]");
}
}
Demo: https://dotnetfiddle.net/uGtw7A
You need a reference to the object causing the exception. However as the instance lives only in the scope of the try-block you can´t access it any more (try and catch don´t share the same scope and thus can´t access the same variables) unless you´d declare the reference to that instance outside the try-bloc
As already mentioned in the comments you should use a normal foreach-loop to have access to the current line:
public static List<int[]> Parse(List<string> list)
{
var result = new List<int[]>();
foreach(var str in list)
{
try
{
var values = str.Split(';');
result.Add(Tuple.Create(
int.Parse(values[0]),
int.Parse(values[1]),
int.Parse(values[2]))
);
}
catch
{
//here in braces I want to know, which element was wrong
throw new FormatException($"Wrong line " + str");
}
}
return result;
}
However you can simply avoid all those exceptions by useing TryParse instead which returns false if parsing failed. So this boils down to something like this:
var values = str.Split(';');
int v0, v1, v2;
if(int.TryParse(values[0], out v0 &&
int.TryParse(values[1], out v1 &&
int.TryParse(values[2], out v2 &&))
result.Add(Tuple.Create(v0, v1, v2));
else
throw new FormatException($"Wrong line " + str");
I recommend manually looping through, splitting the data, checking you have enough elements, and then using TryParse on the numbers. I know this is a departure from using Linq, but it's the better way to do this with error checking:
public static List<int[]> Parse(List<string> list)
{
if (list == null)
{
throw new ArgumentNullException("list");
// you can use nameof(list) instead of "list" in newer versions of C#
}
List<int[]> result = new List<int[]>();
// Loop through the entries
for (int i = 0; i < list.Count; ++i)
{
// Be safe and check we don't have a null value
// I'm just skipping the 'bad' entries for now but
// you can throw an error, etc.
if (list[i] == null)
{
// do something about this? (an exception of your choosing, etc.)
continue;
}
// split the entry
string[] entryData = list[i].Split(';');
// check we have 3 items
if (entryData.Length != 3)
{
// do something about this?
continue;
}
// try to parse each item in turn
int a;
int b;
int c;
if (!int.TryParse(entryData[0], out a))
{
// do something about this?
continue;
}
if (!int.TryParse(entryData[1], out b))
{
// do something about this?
continue;
}
if (!int.TryParse(entryData[2], out c))
{
// do something about this?
continue;
}
// add to the results list
result.Add(new int[] { a, b, c });
}
// return the result
return result;
}
Scope is scope. Anything you define inside your try block and don't explicitly pass on is not going to be available in your catch block.
If you need this information you have to iterate manually over the list and try catch each attempt individually...
There are too many problems with your code, you're assuming that parameter list is not null and contains items that can be splitted in 3 strings, and that every string can be safely parsed to int.
If you not have all the above guaranties just check everything:
public static List<int[]> Parse(List<string> list)
{
if (list == null)
{
throw new ArgumentNullException(nameof(list));
}
var arrayOfStringArray = list
.Select(x => x.Split(';'))
.ToArray();
var resultList = new List<int[]>();
for (var i = 0; i < arrayOfStringArray.Length; i++)
{
var arrayOfString = arrayOfStringArray[i];
if (arrayOfString.Length != 3)
{
throw new InvalidOperationException("meaningfull message there!");
}
var arrayOfInt = new int[3];
for (var j = 0; j < arrayOfInt.Length; j++)
{
arrayOfInt[j] = TryParse(arrayOfString[j], i, j);
}
resultList.Add(arrayOfInt);
}
return resultList;
}
static int TryParse(string value, int line, int position)
{
int result;
if (!int.TryParse(value, out result))
{
throw new FormatException($"Item at position {line},{position} is invalid.");
}
return result;
}
I think that you just got a wrong approach here. Yes, using Tuple + Linq would be the laziest way to get your result but you can't generate custom errors as so.
Here is an example of how you can achieve something alike:
static void Main(string[] args)
{
var result = Parse(new List<string>() { "3;5;7", "qwe;3;70" });
}
public static List<Tuple<int, int, int>> Parse(List<string> list)
{
List<Tuple<int, int, int>> result = new List<Tuple<int, int, int>>();
int line = 0;
int errorCol = 0;
try
{
for (line = 0; line < list.Count; line++)
{
string[] curentLine = list[line].Split(';');
int result0, result1, result2;
errorCol = 1;
if (curentLine.Length > 0 && int.TryParse(curentLine[0], out result0))
errorCol = 2;
else
throw new Exception();
if (curentLine.Length > 1 && int.TryParse(curentLine[1], out result1))
errorCol = 3;
else
throw new Exception();
if (curentLine.Length > 2 && int.TryParse(curentLine[2], out result2))
result.Add(new Tuple<int, int, int>(result0, result1, result2));
else
throw new Exception();
}
return result;
}
catch
{
//here in braces I want to know, which element was wrong
throw new FormatException("Wrong line " + line + " col" + errorCol);
}
}
PS: Line and column start at 0 here.

How to short text alphabetical whit giving value for each character

I was thinking if good way short strings whit character value. Like A = 0, B = 1...
I made some code, but best i get is wrong answer and i think i know where is problem but i dont know what is the problem.
So here is code:
void Start()
{
i = Inventory.instance;
List<Items> items = i.returnList("Food");
Debug.Log(items.Count); List<Items> sItems = GetListSetList(items);
foreach (Items item in sItems)
{
Debug.Log(item.name);
}
}
List items = i.returnList ("Food"); <-- This part is where i ask inventory return all "Food" taged items. Code is here:
public List<Items> returnList(string tag)
{
List<Items> classifiedItemSet = new List<Items>();
foreach (Items i in items)
{
if (i.tag == tag)
{
classifiedItemSet.Add(i);
}
}
return classifiedItemSet;
}
List sItems = GetListSetList (items); <-- This is part where i really try short list what i get from inventory. It looks like this :
private List<Items> GetListSetList(List<Items> itemS)
{
foreach (Items item in itemS)
{
GetAlphabetaValue(item);
}
List<Items> shorted = new List<Items>();
Items[] hold = new Items[itemS.Count];
foreach (Items item in itemS)
{
for (int x = 0; x < hold.Length; x++)
{
if (hold[x] == null)
{
hold[x] = item;
break;
}
else
{
bool PassIt = true;
for (int c_value = 0; c_value < item.Alphabet_value.Length; c_value++)
if (item.Alphabet_value[c_value] > hold[x].Alphabet_value[c_value])
PassIt = false;
if (PassIt)
{
for (int h_pos = hold.Length - 1; h_pos > x; h_pos--)
if (hold[h_pos] != null)
hold[h_pos] = hold[h_pos - 1];
hold[x] = item;
break; // If i use this break i get error ("NullReferenceException")
}
else continue;
}
}
}
for (int x = 0; x < hold.Length; x++)
shorted.Add(hold[x]);
return shorted;
}
Start of this void i give every character in every items name string some value. It is this part : GetAlphabetaValue (item); Oh and sorry naming it AlphaBeta :) Okey how i get this values is this :
private void GetAlphabetaValue(Items x)
{
x.Alphabet_value = new int[x.name.Length];
for (int c = 0; c < x.Alphabet_value.Length; c++)
{
string character = x.name.Substring(c, 1);
character.ToLower();
switch (character)
{
case "a":
x.Alphabet_value[c] = 0;
break;
case "b":
x.Alphabet_value[c] = 1;
break;
case "c":
x.Alphabet_value[c] = 2;
break;
case "d":
x.Alphabet_value[c] = 3;
break;
case "e":
x.Alphabet_value[c] = 4;
break;
case "f":
x.Alphabet_value[c] = 5;
break;
//To the end
}
}
}
I hope you understand what i try to talk :D Thank you :) And i try find some information in internet before i start doing this, but i dont find anything how really can short multiple string from array.
This part i think i got wrong but now i cant just see what wrong whit that :
for (int h_pos = hold.Length - 1; h_pos > x; h_pos--)
if (hold [h_pos] != null)
{
hold [h_pos] = hold [h_pos - 1];
hold [x] = item;
}
use this Code.
string str = "Tamil";
List<char> list = str.ToList ();
list = list.OrderBy(x => x.ToString()).ToList();
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.ReadLine();
To start with do you really think it's a good idea to have a +20 switch-case?
Characters are already numbered, characters a-z in enligsh alphabet correspond to 97-122 chars in Unicode.
This function:
void GetAlphabetaValue(Items x)
{
x.Alphabet_value = new int[x.name.Length];
for (int c = 0; c < x.Alphabet_value.Length; c++)
{
string character = x.name.Substring (c, 1);
character.ToLower ();
switch (character)
{
case "a":
x.Alphabet_value [c] = 0;
break;
///Etc... //Etc..... And end.
}
}
}
Becomes this:
void GetAlphabetaValue2(Items x)
{
var CharIntList = List<int>;
foreach (char ch in x.Name)
CharIntList.Alphabet_value.Add(ch - 97);
x.Alphabet_value = CharIntList.ToArray();
}
Much simpler. Also you code is messy, hard to understand and bad formatted. Probably you are new to C# so you should read about how you are supposed to write code, It's not like I do it well, but other pepole should be able to understand your code.
Then about you question, I think you mean to sort not to short (Completly different things). Also why is Items in plural? it's a singular thing, then it should be Item.
Well, I don't know about your problem, but you can replace your GetListSetList() function to this:
private List<Items> GetListSetList(List<Items> items)
{
foreach (Items item in items)
{
GetAlphabetaValue(item);
Array.Sort(item.Alphabet_value);
}
return items;
}
Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Items> items = Items.returnList("Food");
var groups = items.GroupBy(x => x.name.Substring(0,1)).ToList();
}
}
public class Items
{
public static List<Items> items = new List<Items>();
public string name { get; set; }
public string type { get; set; }
public static List<Items> returnList(string type)
{
return items.Where(x => x.type == type).ToList();
}
}
}

Returning the smallest integer in an arrayList in C#

I recently got asked in a interview to create an method where the following checks are to be made:
Code to check if ArrayList is null
Code to loop through ArrayList objects
Code to make sure object is an integer
Code to check if it is null, and if not then to compare it against a variable containing the smallest integer from the list and if smaller then
overwrite it.
Return the smallest integer in the list.
So I created the following method
static void Main(string[] args)
{
ArrayList list = new ArrayList();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
Program p = new Program();
p.Min(list);
}
private int? Min(ArrayList list)
{
int value;
//Code to check if ArrayList is null
if (list.Count > 0)
{
string minValue = GetMinValue(list).ToString();
//Code to loop through ArrayList objects
for(int i = 0; i < list.Count; i++)
{
//Code to make sure object is an integer
//Code to check if it is null, and if not to compare it against a variable containing the
//smallest integer from the list and if smaller overwrite it.
if (Int32.TryParse(i.ToString(), out value) || i.ToString() != string.Empty)
{
if (Convert.ToInt32(list[i]) < Convert.ToInt32(minValue))
{
minValue = list[i];
}
}
}
}
return Convert.ToInt32(GetMinValue(list));
}
public static object GetMinValue(ArrayList arrList)
{
ArrayList sortArrayList = arrList;
sortArrayList.Sort();
return sortArrayList[0];
}
I think the above is somewhat correct, however am not entirely sure about 4?
I think The following logic may help you. It is simpler than the current and are using int.TryParse() for parsing, which is better than Convert.To..() and int.Parse() Since it has some internal error handling and hence it will will not throw any exception for invalid input. If the input is invalid then it gives 0 to the out variable and returns false, From that we can assume the conversion failed. See the code for this:
var arrayMin = listOfInt;
int currentNum = 0;
int yourNum = int.MaxValue;
bool isSuccess = true;
foreach (var item in listOfInt)
{
if (int.TryParse(item.ToString(), out currentNum) && currentNum <= yourNum)
{
yourNum = currentNum;
}
else
{
isSuccess = false;
break;
}
}
if(isSuccess)
Console.WriteLine("Minimum Number in the array is {0}",yourNum);
else
Console.WriteLine("Invalid input element found");
Simplistic version:
private int? Min(ArrayList list)
{
if (list == null || list.Count == 0) return null;
return list.Cast<int>().Min();
}

Asserting Elements Parsed from XML

I have a class that parses an XML document in C# using XElement.
I parse the XML for example:
IEnumerable<Element> elements =
from topLevelElement in XElement.Parse(xml).Elements("topLevel")
select new Element()
{
LongElement = Int64.Parse(topLevelElement.Element("long").Value),
StringElement = topLevelElement.Element("string").Value,
DateTimeElement = DateTime.Parse(topLevelElement.Element("datetime").Value)
};
What would be the best way to assert that the elements were properly parsed? I would like to check if LongElement, StringElement, and DateTimeElement is not null after parsing, but if there is a better way to go about this, I am open to it.
If you are unsure of the values that may be returned by the elements, you should really be using TryParse e.g.
int i = 0;
string s = "3";
if (Int32.TryParse(s, out i))
{
// Valid integer, now stored in i.
}
else
{
// Invalid integer.
}
Both your data types DateTime and Int32 have TryParse as an available method. As for a string, you can just do a trivial == null or String.IsNullOrEmpty
I would use functions from within Linq. These allow you to either throw an exception or set required defaults if you want your application to be not so strict ;)
Anyways, you get more control:
var elements = from topLevelElement in XElement.Parse(xml).Elements("topLevel")
select new Element()
{
LongElement = ConvertToInt(topLevelElement.Element("long").Value),
StringElement = topLevelElement.Element("string").Value,
DateTimeElement = DateTime.Parse(topLevelElement.Element("datetime").Value)
};
Where within ConvertToInt could do all you want, like:
public int ConvertToInt(object value)
{
if(value is int)
// return converted value
else
// return default, throw exception, etc
}
This is also a more reusable layout.
I would store the parse states in the element as a KeyValuePair:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var states = new string[] { "null", "empty", "noparse", "value" };
var xml = "<root>";
xml += "<topLevel><long>-13451245234</long><string>hello world</string><datetime>1/1/2012 8:00AM</datetime></topLevel>";
xml += "<topLevel><long>4563264643</long><string>lipsum</string><datetime></datetime></topLevel>";
xml += "<topLevel><string>hello world</string><datetime>1/1/2012 8:00AM</datetime></topLevel>";
xml += "</root>";
IEnumerable<Element> elements =
from topLevelElement in XElement.Parse(xml).Elements("topLevel")
select new Element
{
LongElement = ParseValue(topLevelElement, "long"),
DateTimeElement = ParseValue(topLevelElement, "datetime"),
StringElement = ParseValue(topLevelElement, "string"),
};
var idx = 0;
elements.All(e =>
{
Console.WriteLine("---- ELEMENT #{0} -----",idx++);
Console.WriteLine("[long] State: {0}\tValue:{1}\tType:{2}", states[e.LongElement.Key], e.LongElement.Value, (e.LongElement.Value).GetType());
Console.WriteLine("[datetime] State: {0}\tValue:{1}\tType:{2}", states[e.DateTimeElement.Key], e.DateTimeElement.Value, (e.DateTimeElement.Value).GetType());
Console.WriteLine("[string] State: {0}\tValue:{1}\tType:{2}", states[e.StringElement.Key], e.StringElement.Value, (e.StringElement.Value).GetType());
return true;
});
}
private static dynamic ParseValue(XElement parent, String propname)
{
var prop = parent.Element(propname);
dynamic val = null;
byte state = 255;
if (prop == null) state = 0;
else if (string.IsNullOrEmpty(prop.Value)) state = 1;
if (state < 255) return GetKVP(propname, state, GetDefaultValue(propname));
switch (propname)
{
case "string":
state = 3;
val = prop.Value;
break;
case "long":
Int64 longvalue;
if (Int64.TryParse(prop.Value, out longvalue)) { state = 3; val = longvalue; }
else state = 2;
break;
case "datetime":
DateTime datetimevalue;
if (DateTime.TryParse(prop.Value, out datetimevalue)) { state = 3; val = datetimevalue; }
else state = 2;
break;
default:
val = GetDefaultValue(propname);
break;
}
return GetKVP(propname,state,val);
}
private static dynamic GetKVP(string propname, byte state, object val)
{
if (propname == "long") return new KeyValuePair<byte, Int64>(state, (Int64)val);
if (propname == "datetime") return new KeyValuePair<byte, DateTime>(state, (DateTime)val);
if (propname == "string") return new KeyValuePair<byte, String>(state, (String)val);
return null;
}
private static dynamic GetDefaultValue(string propname)
{
if (propname == "long") return long.MinValue;
if (propname == "datetime") return DateTime.MinValue;
if (propname == "string") return null;
return null;
}
#region Nested type: Element
public struct Element
{
// States stored as byte, 0 = null, 1= empty, 2 = has a value
public KeyValuePair<byte,Int64> LongElement { get; set; }
public KeyValuePair<byte,String> StringElement { get; set; }
public KeyValuePair<byte,DateTime> DateTimeElement { get; set; }
}
#endregion
}
}

Categories