I am making an "error code to String" converter that would display the name of an error code from its value, for example 0x000000c3 would give "Class not found", but using MY OWN error codes!
Here's how it actually looks like:
#region errcodes
public int NORMAL_STOP = 0x00000000;
public int LIB_BROKEN = 0x000000a1;
public int RESOURCE_MISSING = 0x000000a2;
public int METHOD_NOT_FOUND = 0x000000a3;
public int FRAMEWORK_ERROR = 0x000000b1;
public int UNKNOWN = 0x000000ff;
#endregion
public string getName(int CODE)
{
}
I would like to get a string value from parameter CODE, in function getName.
How can I do that ?
A good C# practice is using of an enum:
public enum ErrorCode
{
NORMAL_STOP = 0x00000000,
LIB_BROKEN = 0x000000a1,
RESOURCE_MISSING = 0x000000a2,
METHOD_NOT_FOUND = 0x000000a3,
FRAMEWORK_ERROR = 0x000000b1,
UNKNOWN = 0x000000ff
}
public const string InvalidErrorCodeMessage = "Class not found";
public static string GetName(ErrorCode code)
{
var isExist = Enum.IsDefined(typeof(ErrorCode), code);
return isExist ? code.ToString() : InvalidErrorCodeMessage;
}
public static string GetName(int code)
{
return GetName((ErrorCode)code);
}
Another good advice: it would be great to use the C# naming convention for error codes:
public enum ErrorCode
{
NormalStop = 0x00000000,
LibBroken = 0x000000a1,
ResourceMissing = 0x000000a2,
MethodNotFound = 0x000000a3,
FrameworkError = 0x000000b1,
Unknown = 0x000000ff
}
Usage example:
void Main()
{
Console.WriteLine(GetName(0)); // NormalStop
Console.WriteLine(GetName(1)); // Class not found
Console.WriteLine(GetName(ErrorCode.Unknown)); // Unknown
}
Related
I am trying to create some sort of mapping and construct a switch statement based on this.
The first thing I tried was this:
public class Class1
{
public void Test()
{
string testString_A = "A";
string testString_B = null;
switch (testString)
{
case Options.O1.aName:
testString_B = Options.O1.bName;
break;
case Options.O2.aName:
testString_B = Options.O2.bName;
break;
}
}
}
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
public class Option
{
public string aName;
public string bName;
}
In this scenario, compiler complains that a constant value is expected for the switch cases.
So next, I tried the following but it does not work either. The .aName I try to use in the switch statement seems not accessible.
public Class1()
{
public void Test()
{
string testString = "A1";
switch (testString)
{
case Options.O1.aName:
...
}
}
}
public static class Options
{
public static Option_O1 O1 = new Option_O1();
public static Option_O2 O2 = new Option_O2();
}
public class Option_O1
{
public const string aName = "A1";
public const string bName = "B1";
}
public class Option_O2
{
public const string aName = "A2";
public const string bName = "B2";
}
How can I accomplish what I want?
There's a big difference between a string property / field variable (even if it is static or readonly), and a const string. The switch statement requires either literals, or const values in the case statements.
This explains why your first attempt didn't succeed (Error : "A Constant value is required").
In the second case, although you could obviously do this:
switch (testString)
{
case Option_O1.aName:
return Option_O1.bName;
case Option_O2.aName:
return Option_O2.bName;
}
but as soon as you try and 'cheat' the constant switch requirement by introducing the static class container, you're back to the same problem, although a more cryptic compiler error:
case Options.O1.aName: // Cannot be accessed by an instance reference
return Option_O1.bName;
Alternative to switch
I'm guessing here, but it seems that you need to build a run time mapping function.
Assuming that you always want to return the same data type (a string), I would suggest using a Dictionary keyed by the string you are trying to 'switch' on - this mapping can be built up at run time.
Here's an example of a statically bootstrapped map:
public static class Options
{
public static Option O1 = new Option()
{
aName = "A1",
bName = "B1"
};
public static Option O2 = new Option()
{
aName = "A2",
bName = "B2"
};
}
private static IDictionary<string, Option> myOptionMap = new []
{
Options.O1, Options.O2
}
.ToDictionary(x => x.aName);
Which you can use like so:
public string Test(string someAName)
{
if (myOptionMap.TryGetValue(someAName, out var myOption))
{
return myOption.bName;
}
// Oops not found
return string.Empty;
}
Unless there's more to this than your MVP, it's unlikely that you'll want to subclass your options per instance - Option_O1
In Visual Studio I get this error
Argument 1: cannot convert from 'Sintra.frmK1s.ProductStockUpdate' to
'Sintra.ScannetWebService.ProductUpdate'
on this line
int[] updatedResults = Client.Product_Update(updateProduct);
I can't figure it out how I sove this.
Can anyone help?
My code on frmK1s.cs:
using System;
using Sintra.ScannetWebService;
class ProductStockUpdate
{
public string Id;
public int Stock;
}
ProductStockUpdate updateProduct = new ProductStockUpdate();
updateProduct.Id = 5242;
updateProduct.Stock = 100;
int[] updatedResults = Client.Product_Update(updateProduct);
On Sintra.ScannetWebService
public int[] Product_Update(Sintra.ScannetWebService.ProductUpdate ProductData) {
Sintra.ScannetWebService.Product_UpdateRequest inValue = new Sintra.ScannetWebService.Product_UpdateRequest();
inValue.ProductData = ProductData;
Sintra.ScannetWebService.Product_UpdateResponse retVal = ((Sintra.ScannetWebService.WebServicePort)(this)).Product_Update(inValue);
return retVal.Product_UpdateResult;
}
Look at the web service:
public int[] Product_Update(Sintra.ScannetWebService.ProductUpdate ProductData) {
Sintra.ScannetWebService.Product_UpdateRequest inValue = new Sintra.ScannetWebService.Product_UpdateRequest();
inValue.ProductData = ProductData;
Sintra.ScannetWebService.Product_UpdateResponse retVal = ((Sintra.ScannetWebService.WebServicePort)(this)).Product_Update(inValue);
return retVal.Product_UpdateResult;
}
The method is expecting Sintra.ScannetWebService.ProductUpdate object type
You are passing ProductStockUpdate object type:
int[] updatedResults = Client.Product_Update(updateProduct);
class ProductStockUpdate
{
public string Id;
public int Stock;
}
Please pass the correct object to the given method: Sintra.ScannetWebService.ProductUpdate object type:
Sintra.ScannetWebService.ProductUpdate = new Sintra.ScannetWebService.ProductUpdate();
I have been trying to replicate the following C++ function in my C# application but I am getting an AccessViolationException at the time the method "ObjSearchObject2" is invoked. Pretty sure I am doing a lot of things wrong. The C++ function and the corresponding headers looks like this,
bool DocumentSearch(char *pFileId)
{
const int NUM_CONDITIONS = 1;
const int NUM_TYPE_DEFNS = 1;
ObjSearchObjectParm rSearchObject;
ObjSearchCondition rSearchCondition;
ObjObjectResults rSearchResults;
char *pTypeDefnIdArray[NUM_TYPE_DEFNS];
bool bReturnValue = false;
memset(&rSearchObject, 0, sizeof(ObjSearchObjectParm));
memset(&rSearchCondition, 0, sizeof(ObjSearchCondition));
memset(&rSearchResults, 0, sizeof(ObjObjectResults));
pTypeDefnIdArray[0] = "dotdA9";//Documents
rSearchObject.obj_defn_ids = pTypeDefnIdArray;
rSearchObject.obj_defn_count = NUM_TYPE_DEFNS;
rSearchObject.num_conditions = NUM_CONDITIONS;
rSearchObject.max_results = 5000;
rSearchObject.search_cond = &rSearchCondition;
rSearchCondition.field = "ancestor";
rSearchCondition.op = "is";
rSearchCondition.value = pFileId;
if (ObjSearchObject2(&rSearchObject, &rSearchResults))
{
printf("ERROR: ObjSearchObject2 returned: %s \n", ObjGetErrorMsg());
}
else
{
printf("INFO : Number of returned results = %d \n", rSearchResults.num_results);
if (rSearchResults.num_results > 0)
{
for (int iIndex = 0; iIndex < rSearchResults.num_results; iIndex++)
{
if (rSearchResults.object_handle[iIndex])
{
printf("INFO : Object Id returned: %s (name=%s, updated=%s, type=%s, state=%s) \n",
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "id_object"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "name"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "date_update"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "id_type_definition"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "num_state")
);
ObjFreeObjectHdl(rSearchResults.object_handle[iIndex]);
}
}
bReturnValue = true;
}
}
return bReturnValue;
}
int ObjSearchObject2(ObjSearchObjectParm *, ObjObjectResults *);
char * ObjGetObjectAttr(ObjApiObjectHdl objectHdl, char *attr_name);
char * ObjGetErrorMsg();
void ObjFreeObjectHdl(ObjApiObjectHdl objectHdl);
typedef struct _ObjSearchObjectParm {
int obj_defn_count; // mandatory
char **obj_defn_ids; // mandatory
char *text_server_alias; // optional.
char *query_string; // optional text search string
ObjApiBoolean include_deleted; // defaults to OBJAPI_FALSE
int max_results; // default = 200
int num_conditions; // mandatory
ObjSearchCondition *search_cond; // mandatory
ObjApiBoolean include_content; // mandatory for COMPLEX searches, translated to Y/N in API
ObjApiBoolean include_metadata; // mandatory for COMPLEX searches, translated to Y/N in API
} ObjSearchObjectParm;
enum ObjApiSearchOp
{
OBJAPI_MATCH_ALL=1,
OBJAPI_MATCH_ANY=2
};
enum ObjApiBoolean
{
OBJAPI_FALSE,
OBJAPI_TRUE
};
typedef struct _ObjSearchCondition {
ObjApiSearchOp boolop; // only for complex searches
char *join_relation; // only for complex searches
int num_opening_brackets; // only for complex searches
int num_closing_brackets; // only for complex searches
char *field;
char *op;
char *value;
} ObjSearchCondition;
typedef void* ObjApiObjectHdl;
typedef struct _ObjObjectResults {
ObjApiObjectHdl *object_handle;
int num_results;
} ObjObjectResults;
My take on this is as follows, (UPDATE: Code updated)
public class ObjectiveNativeAPI
{
private const string dllPath = #"objapi.dll";
public enum ObjApiBoolean
{
OBJAPI_FALSE,
OBJAPI_TRUE
};
public enum ObjApiSearchOp
{
OBJAPI_MATCH_ALL = 1,
OBJAPI_MATCH_ANY = 2
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ObjSearchObjectParm
{
public int obj_defn_count;
public string[] obj_defn_ids;
public string text_server_alias;
public string query_string;
public ObjApiBoolean include_deleted;
public int max_results;
public int num_conditions;
public IntPtr search_cond;
public ObjApiBoolean include_content;
public ObjApiBoolean include_metadata;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ObjSearchCondition
{
public ObjApiSearchOp boolop;
public string join_relation;
public int num_opening_brackets;
public int num_closing_brackets;
public string field;
public string op;
public string value;
}
[StructLayout(LayoutKind.Sequential)]
public struct ObjObjectResults
{
public IntPtr object_handle;
public int num_results;
}
[DllImport(dllPath, EntryPoint = "ObjSearchObject2")]
public static extern int ObjSearchObject2(ref ObjSearchObjectParm objSearchObjectParm, ref ObjObjectResults objObjectResults);
[DllImport(dllPath, EntryPoint = "ObjGetObjectAttr")]
public static extern string ObjGetObjectAttr(IntPtr object_handle, string attr_name);
[DllImport(dllPath, EntryPoint = "ObjFreeObjectHdl")]
public static extern void ObjFreeObjectHdl(IntPtr object_handle);
}
public void Run()
{
ObjectiveNativeAPI.ObjSearchObjectParm rSearchObject = new ObjectiveNativeAPI.ObjSearchObjectParm();
ObjectiveNativeAPI.ObjSearchCondition rSearchCondition = new ObjectiveNativeAPI.ObjSearchCondition();
ObjectiveNativeAPI.ObjObjectResults rSearchResults = new ObjectiveNativeAPI.ObjObjectResults();
rSearchCondition.field = "ancestor";
rSearchCondition.op = "is";
rSearchCondition.value = txtCotainerId.Text;
rSearchObject.obj_defn_ids = new[] {"dotdA9"};
rSearchObject.obj_defn_count = 1;
rSearchObject.num_conditions = 1;
rSearchObject.max_results = 5000;
IntPtr search_cond = Marshal.AllocCoTaskMem(Marshal.SizeOf(rSearchCondition));
Marshal.StructureToPtr(rSearchCondition, search_cond, false);
rSearchObject.search_cond = search_cond;
int result = ObjectiveNativeAPI.ObjSearchObject2(ref rSearchObject, ref rSearchResults);
MessageBox.Show(string.Format("FunctionResult: {0}", result));
Marshal.FreeCoTaskMem(search_cond);
}
I am a bit lost on this. I have managed to translate some other segments of this project but this is causing me grief. Any help around this would be appreciated.
I often want to parse a string into various bits and have a readable way to return them.
I like this approach, but it involves creating a specific class
long orderID = Utils.UnTradeIdent(tradeIdent).OrderID;
In Utils.cs:
public class TradeIdentData
{
public string AccountIdent;
public long OrderID;
public string SubID;
}
public static TradeIdentData UnTradeIdent(string tradeIdent)
{
TradeIdentData tradeIdentData = new TradeIdentData();
var parts = tradeIdent.Split('!');
tradeIdentData.AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
tradeIdentData.OrderID = long.Parse(bits[1]);
tradeIdentData.SubID = bits[1];
}
else
{
tradeIdentData.OrderID = long.Parse(parts[1]);
tradeIdentData.SubID = "";
}
return tradeIdentData;
}
A separate class with well-named properties (which you are already using) is currently the most readable way of doing this.
In C# 7 you will be able to use tuples for return values, like so:
public static (string AccountIdent, string OrderID, string SubID) UnTradeIdent(string tradeIdent)
{
string accountIdent, orderID, subID ;
... Code to initialise accountIdent, orderID and subID appropriately ...
// Now return the data as a tuple:
return (accountIdent, orderID, subID);
}
You can consume this as follows:
long orderID = Utils.UnTradeIdent(tradeIdent).OrderID;
Or if you want all the values:
var result = Utils.UnTradeIdent(tradeIdent);
// Use result.OrderId, result.SubID or result.AccountIdent
This is not going to be available until some time next year, though.
Also, even though this new tuple support makes it more convenient to WRITE the code, it doesn't let you document it using XML comments as well. Spending the time to write a simple and well-documented class will still often be better than using the new C# 7 tuple support.
See here for more details.
You can also use the out keyword to pass arguments by reference, see MSDN article out (C# Reference):
public static void UnTradeIdent(string tradeIdent, out string AccountIdent, out long OrderID, out string SubID)
{
var parts = tradeIdent.Split('!');
AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
OrderID = long.Parse(bits[1]);
SubID = bits[1];
}
else
{
OrderID = long.Parse(parts[1]);
SubID = "";
}
}
UPDATED with suggestion from comments:
public static bool UnTradeIdent(string tradeIdent, out string AccountIdent, out long OrderID, out string SubID)
{
bool result = false;
AccountIdent = "";
OrderID = 0;
SubID = "";
try
{
var parts = tradeIdent.Split('!');
AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
OrderID = long.Parse(bits[1]);
SubID = bits[1];
}
else
{
OrderID = long.Parse(parts[1]);
SubID = "";
}
}
catch(ArgumentNullException ane)
{
// Handle parsing exception
}
catch (FormatException fe)
{
// Handle parsing exception
}
catch (OverflowException oe)
{
// Handle parsing exception
}
return result;
}
Its pretty simple to do just by changing the return type to dynamic and using an anonymous class
public static dynamic UnTradeIdent(string tradeIdent)
{
var value1 = //parselogic
var value2 = //parselogic
return new { Identity = value1, Item2 = value2};
}
I would consider making additional static methods. Your current implementation is cleaner when you require all of the returned properties, but something like below might be appropriate when you only need one of them.
public static string TradeIdentToAccountIdent(string tradeIdent)
{
var parts = tradeIdent.Split('!');
return parts[0];
}
public static long TradeIdentToOrderID(string tradeIdent)
{
var parts = tradeIdent.Split('!');
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
return long.Parse(bits[1]); // Taken from your example, should probably be bits[0]?
}
else
return long.Parse(parts[1]);
}
// My own take on it this time, you could obviously use your logic as well.
public static string TradeIdentToSubID(string tradeIdent)
{
var order = tradeIdent.Split('!')[1];
if (order.Contains("."))
return order.Split('.')[1];
else
return String.Empty;
}
I have a string of xml node which consists of certain tasks, and a string of project list, I'm iterating through both tasks and project list, and calling a function of another class and passing the tasks and projectlist, but it's giving me an error of best overloaded method and it has some invalid argument. I am assuming that it is a type conversion error.
Here is my code:
private void addtask(object sender,RoutedEventArgs e)
{
foreach (object item in tasklistBox.Items)
{
var listBoxItem = tasklistBox.ItemContainerGenerator.ContainerFromItem(item);
var myContentPresenter = FindVisualChild<ContentPresenter>(listBoxItem);
var myDataTemplate = myContentPresenter.ContentTemplate;
var mydata = (System.Windows.Controls.Label)myDataTemplate.FindName("tasklabel", myContentPresenter);
var xmlElement = (XmlElement)mydata.Content;
//System.Windows.Forms.MessageBox.Show(xmlElement.InnerText);
foreach (Harvest_Project item1 in Globals._globalController.harvestManager._PROJECTLIST)
{
Globals._globalController.harvestManager.assignTaskToProject(xmlElement.InnerText,item1);
}
}
}
and the function of another class which i am calling:
public void assignTaskToProject(Harvest_Task task, Harvest_Project project)
{
Console.WriteLine("Assigning Task to Project");
string assignXML = "<task>" +
"<id type=\"integer\">" + task._id + "</id> " +
"</task>";
sendPOSTRequest(uri + _GETALLPROJECTS + "/" + project._id + "/task_assignments", assignXML);
}
the Harvest_Task class is here:
private bool _billable_by_default;
private bool _deactivated;
private float _default_hourly_rate=0;
public int _id { get; set; }
private bool _is_default;
public string _name { get; set; }
private DateTime _created_at;
private DateTime _updated_at;
private XmlNode _node;
public Harvest_Task()
{ }
public Harvest_Task(XmlNode node)
{
this._node = node;
this._name = node.SelectSingleNode("name").InnerText;
this._created_at = Harvest_Base.storeTime(node.SelectSingleNode("created-at").InnerText);
this._updated_at = Harvest_Base.storeTime(node.SelectSingleNode("updated-at").InnerText);
this._is_default = bool.Parse(node.SelectSingleNode("is-default").InnerText);
this._deactivated = bool.Parse(node.SelectSingleNode("deactivated").InnerText);
float.TryParse(node.SelectSingleNode("default-hourly-rate").InnerText,out this._default_hourly_rate);
this._id = int.Parse(node.SelectSingleNode("id").InnerText);
}
public Harvest_Task(string name, float defaultHourlyRate)
{
this._name = name;
this._default_hourly_rate = defaultHourlyRate;
}
public string createXMLAddEntry()
{
string returnXML = "<task>" +
"<billable-by-default type=\"boolean\">true</billable-by-default>" +
"<default-hourly-rate type=\"decimal\">"+this._default_hourly_rate+"</default-hourly-rate>" +
"<is-default type=\"boolean\">true</is-default>" +
"<name>" + this._name + "</name> " +
"</task>";
return returnXML;
}
the Harvest_Project class is here
public string _name { get; set; }
private DateTime _over_budget_notified_at;
private bool _billable;
private DateTime _created_at;
private bool _active;
private enum _bill_by { Tasks, People, none };
public int _client_id = 0;
private string _code;
private string _notes;
private enum _budget_by { project, project_cost, task, person, none };
private float _budget = 0; //Budget in hrs
private DateTime _latest_record_at;
private DateTime _earliest_record_at;
private int _fees = 0;
public int _id { get; set; }
private DateTime _updated_at;
private XmlNode _node;
public int getId() { return this._id; }
public Harvest_Project(XmlNode node)
{
this._node = node;
this._name = node.SelectSingleNode("name").InnerText;
this._created_at = storeTime(node.SelectSingleNode("created-at").InnerText);
this._updated_at = storeTime(node.SelectSingleNode("updated-at").InnerText);
this._over_budget_notified_at = storeTime(node.SelectSingleNode("over-budget-notified-at").InnerText);
this._latest_record_at = storeTime(node.SelectSingleNode("hint-latest-record-at").InnerText);
this._earliest_record_at = storeTime(node.SelectSingleNode("hint-earliest-record-at").InnerText);
this._billable = bool.Parse(node.SelectSingleNode("billable").InnerText);
try
{
this._id = Convert.ToInt32(getXmlNode("id", node));
this._client_id = Convert.ToInt32(getXmlNode("client-id", node));
this._budget = float.Parse(getXmlNode("budget", node));
this._fees = Convert.ToInt32(getXmlNode("fees", node));
}
catch (OverflowException e)
{
Console.WriteLine("The number cannot fit in an Int32.");
}
catch (FormatException e)
{
Console.WriteLine("The string is not a valid integer");
}
this._code = node.SelectSingleNode("code").InnerText;
this._notes = node.SelectSingleNode("notes").InnerText;
}
this function has Harvest_task and Harvest_Project classes, I am calling this function but unable to call. This line giving an error
Globals._globalController.harvestManager.assignTaskToProject(xmlElement.InnerText,item1);
What conversion to use? I am stuck
Any help? thanks
So far from what I can see you can use this
foreach (Harvest_Project item1 in Globals._globalController.harvestManager._PROJECTLIST)
{
Globals._globalController.harvestManager.assignTaskToProject(new Harvest_Task(xmlElement), item1);
}
I am using the constructor public Harvest_Task(XmlNode node) from the Harvest_Task to create an instance instead of xmlElement.InnerText to be passed as parameter to assignTaskToProject method
I suspect it to fail too as your xml does not have any id and constructor expect node.SelectSingleNode("id").InnerText
You will somehow need to parse the InnerText property to create the type of Harvest_Task - InnerText will be of type string, so it might be a plan to add a 'Converter' class which takes in the string type and outputs a Harvest_Task object.
class HarvestTaskConverter {
public Harvest_Task Convert(string text) {
var task = new Harvest_Task();
// parse the text here
return task;
}
}
Just a couple of additional comments - the method/ variable naming is not very C# - camelCase is preferred, and 'global' variables are generally frowned upon, but it all depends on whether you have control over the other code.