bool flag set to false even though XML Element Exists - c#

I am using a bool flag to check to make sure XML Elements exist before writing them to a variable.
The problem is that I seem to be getting a false negative. I know the element exits because I can see it in the XML sample. However, the flag is still being set to false...
Code Example:
bool flag;
flag = xmlReader.ReadToFollowing("statusCode");
if(flag)
{
statusCode = xmlReader.ReadElementContentAsInt();
}
else
{
statusCode = 333;
}
flag = xmlReader.ReadToFollowing("statusDesc");
if (flag)
{
statusDesc = xmlReader.ReadElementContentAsString();
}
else
{
statusDesc = "";
}
flag = xmlReader.ReadToFollowing("Guid");
if (flag)
{
guid = xmlReader.ReadElementContentAsString();
}
else
{
guid = "";
}
XML Example:
<statusCode>0</statusCode>
<statusDesc/>
<Status/>
<WSKey/>
<Priority/>
<Guid>3A336A97-BCA3-43F8-849C-A40D129B25AA</Guid>
statusCode resolves as true, statusDesc resolves as false, but Guid also resolves as false.
Any ideas?

You may want to consider using LINQ to XML.
The following code snippet worked in my test:
System.Xml.Linq.XDocument temp = System.Xml.Linq.XDocument.Parse("<root><statusCode>0</statusCode><statusDesc/><Status/><WSKey/><Priority/><Guid>3A336A97-BCA3-43F8-849C-A40D129B25AA</Guid></root>");
var t = temp.Descendants("Guid").Any();
Regards,

I got the same result with you. here is the code
class Program {
static void Main(string[] args) {
var s = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<root>" +
"<statusCode>0</statusCode>" +
"<statusDesc/>" +
"<Status/>" +
"<WSKey/>" +
"<Priority/>" +
"<Guid>3A336A97-BCA3-43F8-849C-A40D129B25AA</Guid>" +
"</root>";
var xmlReader = new XmlTextReader(
new MemoryStream(
Encoding.ASCII.GetBytes(s), false));
bool flag;
Int32 statusCode;
String statusDesc;
String guid;
flag = xmlReader.ReadToFollowing("statusCode");
if (flag) {
statusCode = xmlReader.ReadElementContentAsInt();
} else {
statusCode = 333;
}
flag = xmlReader.ReadToFollowing("statusDesc");
if (flag) {
statusDesc = xmlReader.ReadElementContentAsString();
} else {
statusDesc = "";
}
flag = xmlReader.ReadToFollowing("Guid");
if (flag) {
guid = xmlReader.ReadElementContentAsString();
} else {
guid = "";
}
}
}
it seems that the method ReadToFollowing will return false if the element has empty value (e.g. statusDesc). Put a break point at line "flag = xmlReader.ReadToFollowing("statusDesc");" and run the program to that line, if you have a look at the variable xmlReader, its property 'EOF' has been set true. That means it has read to the end of xml. This will explain why it can't find the Guid value in the next call to ReadToFollowing.

Related

C# SAP .net connector not returning the same data as seen in SAP GUI

I have followed the code shown on this site: "https://www.veonconsulting.com/integrating-sap-using-nco/",
I'm trying to get data from the function BAPI_PRODORD_GET_DETAIL, I tested <bapi_prodord_get_detail><number>1000262</number><struct><order_objects><header>X</header><operations>X</operations><components>X</components></order_objects></struct></bapi_prodord_get_detail>, on SAP GUI, I can see data for Header, Components & Operations, but in the code, I 'm not getting the same response, could you please help.
Code:
public bool testConnection()
{
bool state = false;
string rfcRequest = "<RFC_READ_TABLE><QUERY_TABLE>MARD</QUERY_TABLE><DELIMITER>*"
+ "</DELIMITER><ROWSKIPS>0</ROWSKIPS><ROWCOUNT>0</ROWCOUNT><TABLE><OPTIONS><ROW>"
+ "<TEXT>MATNR IN (</TEXT></ROW><ROW><TEXT>'testConnection'</TEXT></ROW><ROW>"
+ "<TEXT>)</TEXT></ROW></OPTIONS></TABLE></RFC_READ_TABLE>";
Utils.RfcClient client = new Utils.RfcClient();
try
{
XElement response = client.PullRequestToSAPrfc(rfcRequest);
state = true;
}
catch (RfcLogonException ex)
{
Console.Write("Logon Failed");
}
catch (RfcInvalidStateException ex)
{
Console.Write("RFC Failed");
}
catch (RfcBaseException ex)
{
Console.WriteLine("communication error" + ex.Message);
}
catch (Exception ex)
{
Console.Write("Connection error");
}
finally
{
//client.disconnectDestination();
}
return state;
}
public bool testConnection()
{
bool state = false;
string rfcRequest = "<bapi_prodord_get_detail><number>1000262</number><struct>"
+ "<order_objects><header>X</header><operations>X</operations><components>X"
+ "</components></order_objects></struct></bapi_prodord_get_detail>";
Utils.RfcClient client = new Utils.RfcClient();
try
{
XElement response = client.PullRequestToSAPrfc(rfcRequest);
state = true;
}
catch (RfcLogonException ex)
{
Console.Write("Logon Failed");
}
catch (RfcInvalidStateException ex)
{
Console.Write("RFC Failed");
}
catch (RfcBaseException ex)
{
Console.WriteLine("communication error" + ex.Message);
}
catch (Exception ex)
{
Console.Write("Connection error");
}
finally
{
//client.disconnectDestination();
}
return state;
}
public XElement PullRequestToSAPrfc(string XMLRequest)
{
IRfcFunction requestFn;
requestFn = PrepareRfcFunctionFromXML(XElement.Parse(XMLRequest));
RfcSessionManager.BeginContext(_ECCsystem);
requestFn.Invoke(_ECCsystem);
RfcSessionManager.EndContext(_ECCsystem);
XElement XMLResponse = PrepareXMLFromrfc(requestFn);
return XMLResponse;
}
public IRfcFunction PrepareRfcFunctionFromXML(XElement xmlFunction)
{
RfcRepository repo = _ECCsystem.Repository;
IRfcFunction RfcFunction = repo.CreateFunction(xmlFunction.Name.ToString());
foreach (XElement xelement in xmlFunction.Elements())
{
if (xelement.Name.ToString().Equals("TABLE"))
{
if (NotProcessSpecialTable(xelement))
continue;
IRfcTable options = RfcFunction.GetTable(xelement.Descendants().First().Name.ToString());
foreach (XElement row in xelement.Elements().First().Elements())
{
options.Append();
foreach (XElement rowElement in row.Elements())
{
string elementName = rowElement.Name.ToString();
RfcElementMetadata elementMeta = options.GetElementMetadata(elementName);
var elementValue = getValueAsMetadata(ref elementMeta, rowElement.Value);
if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
options.SetValue(elementName, elementValue);
}
}
}
else if (xelement.Name.ToString().Equals("STRUCT"))
{
IRfcStructure options = RfcFunction.GetStructure(xelement.Descendants().First().Name.ToString());
foreach (XElement structElement in xelement.Elements().First().Elements())
{
string elementName = structElement.Name.ToString();
RfcElementMetadata elementMeta = options.GetElementMetadata(elementName);
var elementValue = getValueAsMetadata(ref elementMeta, structElement.Value);
if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
options.SetValue(elementName, elementValue);
}
}
else
{
string elementName = xelement.Name.ToString();
RfcElementMetadata elementMeta = RfcFunction.GetElementMetadata(elementName);
var elementValue = getValueAsMetadata(ref elementMeta, xelement.Value);
if (elementValue is string && string.IsNullOrEmpty((string)elementValue)) { continue; }
RfcFunction.SetValue(elementName, elementValue);
}
}
return RfcFunction;
}
public XElement PrepareXMLFromrfc(IRfcFunction rfcFunction)
{
var XMLRoot = new XElement(rfcFunction.Metadata.Name);
for (int functionIndex = 0; functionIndex < rfcFunction.ElementCount; functionIndex++)
{
var functionMatadata = rfcFunction.GetElementMetadata(functionIndex);
if (functionMatadata.DataType == RfcDataType.TABLE)
{
var rfcTable = rfcFunction.GetTable(functionMatadata.Name);
var XMLTable = new XElement(functionMatadata.Name);
foreach (IRfcStructure rfcStracture in rfcTable)
{
XElement XMLRow = new XElement("ROW");
for (int i = 0; i < rfcStracture.ElementCount; i++)
{
RfcElementMetadata rfcElementMetadata = rfcStracture.GetElementMetadata(i);
if (rfcElementMetadata.DataType == RfcDataType.BCD)
{ XMLRow.Add(new XElement(rfcElementMetadata.Name, rfcStracture.GetString(rfcElementMetadata.Name))); }
else
{
XMLRow.Add(new XElement(rfcElementMetadata.Name, rfcStracture.GetString(rfcElementMetadata.Name)));
}
}
XMLTable.Add(XMLRow);
}
XMLRoot.Add(XMLTable);
}
else if (functionMatadata.DataType == RfcDataType.STRUCTURE)
{
var rfcStructure = rfcFunction.GetStructure(functionMatadata.Name);
XElement XMLRow = new XElement(functionMatadata.Name);
for (int elementIndex = 0; elementIndex < rfcStructure.ElementCount; elementIndex++)
{
RfcElementMetadata eleMeta = rfcStructure.GetElementMetadata(elementIndex);
XMLRow.Add(new XElement(eleMeta.Name, rfcStructure.GetString(eleMeta.Name)));
}
XMLRoot.Add(XMLRow);
}
else
{
RfcElementMetadata rfcElement = rfcFunction.GetElementMetadata(functionIndex);
XMLRoot.Add(new XElement(rfcElement.Name, rfcFunction.GetString(rfcElement.Name)));
}
}
return XMLRoot;
}
# Below function is used for the data types.
private object getValueAsMetadata(ref RfcElementMetadata elementMeta, string value)
{
switch (elementMeta.DataType)
{
case RfcDataType.BCD:
return value;
case RfcDataType.NUM:
if (value.Contains("."))
{
int elementValue;
int.TryParse(value, out elementValue);
return elementValue;
}
else
{
return Convert.ToInt32(value);
}
case RfcDataType.INT1:
return Convert.ToInt32(value);
case RfcDataType.INT2:
return Convert.ToInt32(value);
case RfcDataType.INT4:
return Convert.ToInt32(value);
case RfcDataType.INT8:
return Convert.ToInt64(value);
case RfcDataType.CHAR:
return value;
case RfcDataType.DATE:
return DateTime.ParseExact(value, "yyyy-MM-dd", CultureInfo.InvariantCulture);
default:
return string.Empty;
}
}
You are confronted to the classic issue of external and internal values in SAP.
Your screenshot shows the ABAP Function Module Test screen in SAP system. When you enter a value in the screen, it may be transformed internally before calling the function module.
These are called the external and internal formats. "External" is what is shown in the User Interface (typed or displayed), "internal" is the value written to the database.
For instance, imagine a database object whose primary key is a GUID, this is the object key in internal format, but in the user interface this object is always referred or shown by its name (candidate key).
In your precise case, when a Production Order is a number, the internal format always contains leading zeroes on 12 digits, and the external format does not display them. In the Function Module Test screen, if you enter this external value:
1000262
it's converted to the following internal value and the BAPI is called with it:
000001000262
Generally speaking, when you call any function module from another program, you must indicate the internal value, because there's no user interface implied between the two.
i.e., use this XML in your method testConnection:
string rfcRequest = "<bapi_prodord_get_detail><number>000001000262</number><struct>"
+ "<order_objects><header>X</header><operations>X</operations><components>X"
+ "</components></order_objects></struct></bapi_prodord_get_detail>";
See also this answer about external and internal formats: Converting MATNR via conversion exit fails for custom table
If you would like to do the required field conversions programmatically, which are explained in Sandra Rossi's answer, you may use the RFMs BAPI_CONVERSION_EXT2INT, BAPI_CONVERSION_EXT2INT1, BAPI_CONVERSION_INT2EXT and BAPI_CONVERSION_INT2EXT1 for doing so.
However, every additional RFC call has of course a negative impact on the performance.
Besides, SAP Note 206068 is a good resource for an explanation of some RFC BAPI pitfalls which you also stepped in.

Algorithm for retry process

Let say that we have a series of function that needs to execute in a loop.
Get Setttings return networkPath & localPath.
Copy File from networkPath(from process 1) to another localPath.
Read file from localPath return list of info.
Save list of info into DB.
In normal execution I have this code.
public void StartProcess() {
var settings = GetSettings();
CopyFiles(settings);
var listOfData = ReadFile(settings);
SaveListOfData(listOfData);
}
StartProcess method will be executed in a loop in which it waits for a file to read.
What would be a nice way to handle in which a program/code can retry specific process?
For example there's an error on number 2 process, the program should execute process 2 and skip process 1.
In this case you can use boolean variable to control this situation.
bool successrun = true;
string settings = ""; // variable type should be same with return type of GetSettings()
public void StartProcess()
{
if (successrun == true)
settings = GetSettings();
successrun = true;
//set successran = false on any error on the following mwthods
CopyFiles(settings);
var listOfData = ReadFile(settings);
SaveListOfData(listOfData);
}
For more than 2 processes :
string settings = ""; // variable type should be same with return type of GetSettings()
public void StartProcess()
{
if (successrun == true)
settings = GetSettings();
successrun = true;
//set successran = false on any error on the following mwthods
CopyFiles(settings);
var listOfData = ReadFile(settings);
SaveListOfData(listOfData);
}
void AnyMethodCallsStartProcessInLoop()
{
int numberOfProcesses = GetNumberOfProcesses();
int i = 0;
bool procSuccess = true;
while ( i <= numberOfProcesses)
{
StartProcess();
if (procSuccess == true)
i++;
}
}

"Error: Not all code paths return a value."

My code, upon compilation, throws the titular exception. I don't understand why this happens because after extensive searching the reason the error occurs is seemingly only when conditions exist where there is no exit return statement, and yet I think my code is fully inclusive.
bool CheckExisting()
{
Account loginAcc = new Account();
string path = Application.StartupPath.ToString() + "\\Customers";
int fCount = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories).Length;
for(int i = 0;i<fCount;i++)
{
String[] filePaths = Directory.GetFiles(Application.StartupPath + "\\Customers\\");
XmlDocument xmlFile =new XmlDocument();
xmlFile.Load(filePaths[i]);
foreach(XmlNode node in xmlFile.SelectNodes("//Account"))
{
string firstName = node.SelectSingleNode("FirstName").InnerText;
string lastName = node.SelectSingleNode("LastName").InnerText;
string address1 = node.SelectSingleNode("Address1").InnerText;
string address2 = node.SelectSingleNode("Address2").InnerText;
string postCode = node.SelectSingleNode("Postcode").InnerText;
string telePhone = node.SelectSingleNode("Telephone").InnerText;
string mobile = node.SelectSingleNode("Mobile").InnerText;
Account newAcc = new Account();
newAcc.firstName = firstName;
newAcc.lastName = lastName;
newAcc.address1 = address1;
newAcc.address2 = address2;
newAcc.postCode = postCode;
newAcc.telephone = telePhone;
newAcc.mobile = mobile;
loginAcc = newAcc;
}
if(txtFirstName.Text == loginAcc.firstName && txtLastName.Text == loginAcc.lastName)
{
return true;
}
else
{
return false;
}
return false;
}
}
Your code is effectively:
bool CheckExisting()
{
// Some setup code
for (int i = 0; i < fCount; i++)
{
// Code which isn't terribly relevant
return ...;
}
}
Now the C# 5 language specification section 8.8.3 talks about the reachability of the end of a for statement:
The end point of a for statement is reachable if at least one of the following is true:
The for statement contains a reachable break statement that exits the for statement.
The for statement is reachable and a for-condition is present and does not have the constant value true.
The latter is true in this case, so the end of the for statement is reachable... and that's the end of the method. The end of a method with a non-void return type can never be reachable.
Note that this is the case even if a human could detect that you can never reach the end of the for statement. For example:
bool Broken()
{
for (int i = 0; i < 5; i++)
{
return true;
}
// This is still reachable!
}
We know that the loop will always execute at least once, but the language rules don't - therefore the end of the statement is reachable, and you get a compile-time error.
If fCount were to be 0 then your loop would not execute and you'll not hit any of the return statements.
Some condensing and improved indentation makes it clear:
int fCount = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories).Length;
for(int i = 0;i<fCount;i++){
...
if(txtFirstName.Text == loginAcc.firstName && txtLastName.Text == loginAcc.lastName){
return true;
}
else{
return false;
}
return false;
}
Possibly in the "real world" fCount can never be 0, however compiler/runtime won't know this.
That happened because after for loop you have returned Nothing.
When your method executes it is expected to return the type you defined. When the code execution path goes into your for statement, it is fine because it returns. If the code does NOT go into the for loop, that your code does not return anything. That is the error. Run time exception likely .Walk through the code with pencil and paper and see how it executes
You missed a return. This should work.
bool CheckExisting()
{
Account loginAcc = new Account();
string path = Application.StartupPath.ToString() + "\\Customers";
int fCount = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories).Length;
for(int i = 0;i<fCount;i++)
{
String[] filePaths = Directory.GetFiles(Application.StartupPath + "\\Customers\\");
XmlDocument xmlFile =new XmlDocument();
xmlFile.Load(filePaths[i]);
foreach(XmlNode node in xmlFile.SelectNodes("//Account"))
{
string firstName = node.SelectSingleNode("FirstName").InnerText;
string lastName = node.SelectSingleNode("LastName").InnerText;
string address1 = node.SelectSingleNode("Address1").InnerText;
string address2 = node.SelectSingleNode("Address2").InnerText;
string postCode = node.SelectSingleNode("Postcode").InnerText;
string telePhone = node.SelectSingleNode("Telephone").InnerText;
string mobile = node.SelectSingleNode("Mobile").InnerText;
Account newAcc = new Account();
newAcc.firstName = firstName;
newAcc.lastName = lastName;
newAcc.address1 = address1;
newAcc.address2 = address2;
newAcc.postCode = postCode;
newAcc.telephone = telePhone;
newAcc.mobile = mobile;
loginAcc = newAcc;
}
if(txtFirstName.Text == loginAcc.firstName && txtLastName.Text == loginAcc.lastName)
{
return true;
}
else
{
return false;
}
return false;
}
return false;
}
bool CheckExisting(){
Account loginAcc = new Account();
string path = Application.StartupPath.ToString() + "\\Customers";
int fCount = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories).Length;
for(int i = 0;i<fCount;i++){
String[] filePaths = Directory.GetFiles(Application.StartupPath + "\\Customers\\");
XmlDocument xmlFile =new XmlDocument();
xmlFile.Load(filePaths[i]);
foreach(XmlNode node in xmlFile.SelectNodes("//Account")){
string firstName = node.SelectSingleNode("FirstName").InnerText;
string lastName = node.SelectSingleNode("LastName").InnerText;
string address1 = node.SelectSingleNode("Address1").InnerText;
string address2 = node.SelectSingleNode("Address2").InnerText;
string postCode = node.SelectSingleNode("Postcode").InnerText;
string telePhone = node.SelectSingleNode("Telephone").InnerText;
string mobile = node.SelectSingleNode("Mobile").InnerText;
Account newAcc = new Account();
newAcc.firstName = firstName;
newAcc.lastName = lastName;
newAcc.address1 = address1;
newAcc.address2 = address2;
newAcc.postCode = postCode;
newAcc.telephone = telePhone;
newAcc.mobile = mobile;
loginAcc = newAcc;
}
if(txtFirstName.Text == loginAcc.firstName && txtLastName.Text == loginAcc.lastName){
return true;
}
else{
return false;
}
return false;
}
??????
}
not returning anything if you are not entering into the for loop.
or you are not returning anything if your "FCount" is "0".
To put it simply, just add a default return false at the end. Here's your code snippet:
if(txtFirstName.Text == loginAcc.firstName && txtLastName.Text == loginAcc.lastName)
{
return true;
}
else
{
return false;
}
return false;
}
return false;
}
Just think about the case scenario where fCount is zero or less than it.
for(int i = 0;i<fCount;i++)
The for loop will be skipped. So where's the return statement for that? That's why the compiler is throwing this error.
I think you meant to do this: (I'm stealing CodeCaster's cleaned up version)
bool CheckExisting()
{
//
for(/**/)
{
//
foreach(/**/)
{
//
}
if(/**/)
{
return true;
}
else
{
return false;
}
// return false; NOT HERE, because it's not reachable in the first place.
}
return false; // BUT HERE, in case fCount = 0
}
Also, you could do away with the if-else at the end and just do
return txtFirstName.Text == loginAcc.firstName && txtLastName.Text == loginAcc.lastName;
... since that's a boolean expression already.

Overwriting xml file #2

I'm trying to edit an xml and then save it with the same name.
I have the following code:
public int ModifyFile(string xmlpath, string option, int returnCode)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlpath);
XmlNode parentNode = xmlDoc.DocumentElement;
if (option.Equals("delete"))
{
returnCode = DeleteTag(parentNode, "identity", returnCode);
}
xmlDoc.Save(xmlpath);
return returnCode;
}
public int DeleteTag(XmlNode root, string deleteName, int returnCode)
{
foreach (XmlNode node in root.ChildNodes)
{
if (node.Name == deleteName)
{
root.RemoveChild(node);
returnCode = 1;
}
else
{
returnCode = DeleteTag(node, deleteName, returnCode);
}
}
return returnCode;
}
I'm getting "The process cannot access the file 'c:\temp\testfile.xml' because it is being used by another process" when it executes xmlDoc.Save(path).
How would I be able to save testfile.xml with the changes made? I need to keep the path and name the same.
public static bool hasIdentityTag(string path)
{
bool isTextPresent = false;
if (File.Exists(path))
{
XmlTextReader rdrXml = new XmlTextReader(path);
do
{
switch (rdrXml.NodeType)
{
case XmlNodeType.Element:
if (rdrXml.Name.Equals("identity"))
{
isTextPresent = true;
rdrXml.Close();
}
break;
}
} while (rdrXml.Read());
}
else
{
Console.WriteLine("The file {0} could not be located", path);
}
return isTextPresent;
}
One option would be to save the new XML to a temporary file, close the XmlDocument and dispose of the object, then move the temporary file back to the right place.
You could try this re-write using LinqToXml:
XElement root = XElement.Load(xmlpath);
bool modified = false;
try
{
switch(option)
{
case "delete":
var toDelete = root.Descendants("identity").ToArray();
foreach(XElement x in toDelete)
{
x.Remove();
modified = true;
returnCode = 1;
}
break;
}
}
finally
{
if(modified)
root.Save(xmlpath);
}
return returnCode;
How about loading the XmlDocument from a Stream instead of by file name? If you still encounter errors, this would indicate that something outside of your method/process is blocking the save.
Try rewriting theModifyFile method like this:
public int ModifyFile(string xmlpath, string option, int returnCode)
{
var fs = File.Open(xmlpath);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fs); // use the stream, not file name
fs.Close(); // now close the stream... file should not be locked from this point
XmlNode parentNode = xmlDoc.DocumentElement;
if (option.Equals("delete"))
{
returnCode = DeleteTag(parentNode, "identity", returnCode);
}
xmlDoc.Save(path);
return returnCode;
}

Unhandled exception, unable to debug

I'm trying to debug my c# application that check MIPS syntax. But its not allowing be to debug it. No matter where I enter my break point it gets ignored, including the first line of the Main() function. Its also throwing me this error.
'add a b c' works fine if i don't call HasValidParams()
'add a b' throws exception in the same situation
neither works when calling HasValidParams()
program.cs
private static void Main(string[] args)
{
var validator = new MipsValidator();
Console.Write("Please enter a MIPS statement: ");
string input = Console.ReadLine();
List<string> arguments = input.Split(new char[0]).ToList();
Response status = validator.IsSyntaxValid(arguments);
//Check syntax
if (status.Success.Equals(true))
{
Response stat = validator.HasValidParams(arguments);
//Check parameters
if (stat.Success.Equals(true))
{
Console.WriteLine(string.Format("'{0}' is a valid mips instruction ", input));
}
else
{
foreach (var reason in stat.Reasons)
{
Console.WriteLine(reason);
}
}
}
else
{
foreach (string reason in status.Reasons)
{
Console.WriteLine(reason);
}
}
}
mips-validator.cs
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace mips_validator.utils
{
public class MipsValidator : IMipsValidator
{
#region Implementation of IMipsValidator
public Response IsSyntaxValid(List<string> args)
{
var response = new Response {Success = true};
var op = (Operator) Enum.Parse(typeof (Operator), args[0]);
switch (op)
{
case Operator.addi:
case Operator.add:
case Operator.beq:
if (args.Count != 4)
{
response.Reasons.Add(string.Format("4 operands required for {0}, {1} parameters provided.",
op, args.Count));
response.Success = false;
}
break;
case Operator.j:
if (args.Count != 2)
{
response.Reasons.Add(string.Format("1 operands required for {1}, {0} parameters provided.",
args.Count, op));
response.Success = false;
}
break;
default:
response.Reasons.Add(string.Format("{0} is an unknown mips operation", op));
response.Success = false;
break;
}
return response;
}
public Response HasValidParams(List<string> parameters)
{
string op1, op2, op3;
var temporary = new Regex(#"/\$t\d+/");
var store = new Regex(#"/\$s\d+/");
var zero = new Regex(#"/\$zero/");
var osReserved = new Regex(#"/\$k0|1/");
var memory = new Regex(#"");
var constant = new Regex(#"/-?\d*/");
var label = new Regex(#"/.*\:/");
Operator operation;
var response = new Response {Success = true};
string opString = parameters[0];
Enum.TryParse(opString.Replace("$", string.Empty), true, out operation);
switch (operation)
{
case Operator.add:
{
op1 = parameters[1];
op2 = parameters[2];
if (!temporary.IsMatch(op1) && !store.IsMatch(op1) && !zero.IsMatch(op1))
{
response.Reasons.Add(string.Format("{0}: error register expected", op1));
response.Success = false;
}
if (!temporary.IsMatch(op2) && !store.IsMatch(op2) && !zero.IsMatch(op2))
{
response.Reasons.Add(string.Format("{0}: error register expected", op2));
response.Success = false;
}
}
break;
case Operator.addi:
{
op1 = parameters[1];
op2 = parameters[2];
if (!temporary.IsMatch(op1) && !store.IsMatch(op1) && !zero.IsMatch(op1))
{
response.Reasons.Add(string.Format("{0}: error register expected", op1));
response.Success = false;
}
if (!constant.IsMatch(op2) && !zero.IsMatch(op2))
{
response.Reasons.Add(string.Format("{0}: error constant expected", op2));
response.Success = false;
}
}
break;
case Operator.beq:
{
op1 = parameters[1];
op2 = parameters[2];
op3 = parameters[3];
if (!temporary.IsMatch(op1) && !store.IsMatch(op1) && !zero.IsMatch(op1))
{
response.Reasons.Add(string.Format("{0}: error register expected", op1));
response.Success = false;
}
if (!temporary.IsMatch(op2) && !store.IsMatch(op2) && !zero.IsMatch(op2))
{
response.Reasons.Add(string.Format("{0}: error register expected", op2));
response.Success = false;
}
if (!label.IsMatch(op3) && !constant.IsMatch(op3))
{
response.Reasons.Add(string.Format("{0}: error label or constant expected", op3));
response.Success = false;
}
}
break;
}
return response;
}
#endregion
}
}
SOLUTION-------
Response.cs(old)
public class Response
{
public List<string> Reasons;
public bool Success = true;
}
Response.cs(current)
public class Response
{
public Response()
{
Reasons = new List<string>();
Success = true;
}
public List<string> Reasons;
public bool Success = true;
}
I can't tell if you're looking for a way to be able to debug your project or if you'd prefer to be told potential issues in your code.
For the latter:
Make sure Response.Reasons is initialized by the constructor of Response (or a field initializer).
You're not showing the Response class, so make sure Reasons is actually set to a collection you can add to and not left to the default, null.
Edit: The below possible cause for a crash was pointed put by #nodakai not to be one at all; turns out an empty char array is a special case to split on whitespace.
*You calculate arguments by doing
List arguments = input.Split(new char[0]).ToList();
...which as far as I can tell does absolutely nothing except put the original string inside a List. You probably want to split on new char[] {' '} instead to split on spaces.*
Check if your breakpoint looks like this:
If it does, your source code differs from the code the assembly was actually compiled with. Make sure your project is built properly (right click on the solution and select "Rebuild") and check your current configuration:
Hope this helps...

Categories