|
Hi Keith,
In my humble opinion, in an "ideal" CodeProject, there'd be a special place for responses like this which speak so eloquently of the human condition !
best, Bill
"In the River of Delights, Panic has not failed me." Jorge Luis Borges
|
|
|
|
|
You could check this out:
VolumeMeter (Managed DirectX)[^]
Continuous effort - not strength or intelligence - is the key to unlocking our potential.(Winston Churchill)
|
|
|
|
|
Hi,
I have many constants, each recurring as per country and declared in class as below:
class CountryRequests
{
public const string JAP_ABC="JAP_012686";
public const string JAP_PQR="JAP_012457";
public const string JAP_POP="JAP_0178WE";
public const string US_ABC="US_015788";
public const string US_PQR="US_077895";
public const string US_POP="US_8726JI";
public const string EGN_ABC="GB_678756";
public const string ENG_PQR="GB_567766";
public const string ENG_POP="GB_8962KL";
}
and I have multiple functions each accessing string for every country, evaluated as
if(country == 'JAP')
{
}
else if(country == 'US')
{
}
else if(country == 'UK')
{
}
occuring multile times.
What is best coding here. I cannot change from CountryRequests class to collection as it is used by multiple projects.
Please advice.
Thank you.
***** Programme comme si dept soutien technique. est plein de tueurs en série et ils savent adresse de votre domicile. *****
|
|
|
|
|
But in your project you can set a bunch of dictionaries on top of the common CountryRequests class. Using reflection, you should be able to extract all those const string from the class, filter them by their names and set up a dictionary per country.
Then, on changing the country variable you could switch the currently used dictionary, too. That way you wouldn't have to branch in every function.
Ciao,
luker
|
|
|
|
|
Not really sure what you want to know here. If you're saying that you can't change the CountryRequests class, then your options are severely limited.
I imagine you're trying to avoid lots of switch or if statements. As stated, you could try to use a mechanism such as reflection, but I'm not sure that will work with constants as I think they only really exist until the compiler does its stuff. They make it into metadata as well, not sure. (You can get into trouble with constants if you expect them to be late bound - they're not).
Personally, I don't think you should ever build logic which relies on source objects having particular names (concatinating two strings to create a type name you create using Activator.CreateInstance for example). People can change names and things will compile but break at runtime.
Suggestion would be to create one single switch statement which takes a string such as JAP_ABC and returns the constant value of JAP_ABC. You can't avoid doing this sort of thing somewhere, so do it in one place only. Hand coding it will give you compiler checks and detect any changes to the constants on recompiling too.
Regards,
Rob Philpott.
|
|
|
|
|
I agree. Since you can't change the source class, you really don't have any options here.
It's ridiculous to have a Class with nothing but a ton of "magic number" constants in it like this.
This should have been implemented from the start as a Key/Value pair collection, like a Dictionary(). What's odd is that someone should have looked at even this small code snippet and noticed the pattern is just begging to be implemented as a Dictionary.
|
|
|
|
|
I suspect that what you really want is a family of classes, one for each country. (If not a database.)
Even if you can't change the class, you may be able to copy its contents to some other (more suitable) structure via Reflection. This assumes your app runs for a decent length of time rather than only a few seconds at a time.
Another possibility would be to write a little console app that will perform that task at compile time (pre-build event) and yield a file containing the appropriate classes. Your main app would then use the generated classes. This could also be done to yield a single class that only contains a Dictionary of the keys and values.
I'd need to know more about what the app is doing.
|
|
|
|
|
JP_Rocks wrote: I have many constants, each recurring as per country and declared in class as below:
class CountryRequests
{
public const string JAP_ABC="JAP_012686";
public const string JAP_PQR="JAP_012457";
I'd go for an enum, like this;
enum CountryRequests
{
JAP_012686,
JAP_012457
}
That way they're grouped, like constants in a class, and you can still use the string-version by calling JAP_012686.ToString() - that would give you the same result as the content of the constant.
JP_Rocks wrote: What is best coding here
That depends on your type of application. Long lookup-lists are happy in a local embedded database, other times you might want to centralize the information (so that updating it is easy), and move to a central database, or a resource-assembly.
JP_Rocks wrote: I cannot change from CountryRequests class to collection as it is used by multiple projects.
That the class is used often is not an excuse. You can easily write a new class that can be used as a substitute; dive into the "L" part of the SOLID-principle
Bastard Programmer from Hell
|
|
|
|
|
Just refractor the if statement into the CountryRequests class to return the code. I'm guessing there would need to be an extra parameter to handle the ABC, PQR suffix.
public void GetCountryRequestCode(string countryCode)
{
switch (countryCode)
{
Case "JAP":
return JAP_ABC;
....
}
}
"You get that on the big jobs."
|
|
|
|
|
JP_Rocks wrote: I cannot change from CountryRequests class to collection as it is used by multiple projects. One question: is the CountryRequests class in a library that is now being compiled, and which the other projects are now using by embedding a reference to the compiled class ? In other words, are all the projects using CountryRequests under your source-control scope ?
I ask this because of the fact that the compiler in-lines const types where they are referenced, and unless both the CountryRequests class, and all other projects using it are re-compiled together, a client class may persist an out of date value[^].
The idea of using Reflection to pre-compile ... say by using 'Emit ... a "hard-coded" look-up to replace a big Switch statement might be worthwhile if these constant values were being accessed with great frequency, but I doubt that's the case here.
Another idea, based on the constraint that you can't touch 'CountryRequests," would be to create a kind of "singleton" class that effectively "extends" it through inheritance.
disclaimer: experimental: this code tested quickly in VS 2010 Pro, .NET 4.0 Client FrameWork; I have no idea what the implications of using this type of inherited class with call to a private (internal) constructor done by a public static method in a variation on the "singleton" technique, and using a mix of static and public classes might mean in a real-world use case of multi-threaded environment, remoting, multiple consumers of the class, etc.:
public class CountryRequestsServer : CountryRequests
{
internal static CountryRequestsServer instanceCRServer;
internal static Dictionary<string, string> countryLookUp;
internal CountryRequestsServer()
{
countryLookUp = new Dictionary<string, string>()
{
{"JAP", JAP_ABC},
{ "USA", US_POP},
{ "UK", ENG_POP}
};
}
public static string getCountry(string request)
{
if(instanceCRServer == null)
{
instanceCRServer = new CountryRequestsServer();
}
return countryLookUp.ContainsKey(request)
?
countryLookUp[request]
:
"No Match: Input = " + request;
}
} Tested like this:
string myCountryRequest = CountryRequestsServer.getCountry("JAP");
good luck, Bill
"In the River of Delights, Panic has not failed me." Jorge Luis Borges
|
|
|
|
|
BillWoodruff wrote: using Reflection ... with great frequency
In which case I recommend caching the results of the Reflection. Perhaps you meant that, but didn't make it clear.
I don't see that a Singleton gives you any benefit over a static class in this example.
|
|
|
|
|
What you want to do is change this into a family of 'pseudoconstant' instances, or a database table:
public class CountryInfo {
public readonly string ABC, POP, PQR, ...;
private CountryInfo(string abc, string pop, string pqr ...){
ABC = abc; POP = pop; PQR = pqr;
}
public static readonly CountryInfo
JAP = new CountryInfo(CountryRequests.JAP_ABC, CountryRequests.JAP_POP, CountryRequests.JAP_PQR, ...),
UK = new CountryInfo(CountryRequests. UK_ABC, CountryRequests. UK_POP, CountryRequests. UK_PQR, ...),
US = new CountryInfo(CountryRequests. US_ABC, CountryRequests. US_POP, CountryRequests. US_PQR, ...),
}
You still have to define all the constants, but now you don't need to put a switch everywhere. Just pass a CountryInfo (e.g. CountryInfo.JAP) and access the strings through the instance:
void CountryDependentFunction(CountryInfo countryInfo){
someFunction(countryInfo.POP);
}
Even if you don't have enough control to replace or modify CountryRequests, you should be able to put this on top of it. If CountryRequests changes frequently you can write a script to update the lower part of CountryInfo, or you could put some static initialiser reflection in there to load entries at runtime (but then you would have to use a dictionary and indexing and it wouldn't be as nice as using properties, as well as being needlessly complex for most situations).
|
|
|
|
|
Hi, CP. I have a database hosted on an instance of SQL Server 2008 Express. I am using C# (.NET 4.0) and VS2010. I created a junction table in order to use a many-to-many relationship between two tables. I retrieve and manipulate data primarily using the main table but a part of the application requires me to find the most common value for a particular field, which is stored in a junction table.
For example, I call a SELECT statement which retrieves the fields from the table [Repair Data]. The junction table, [Failure Codes], contains the fields [Serial Number] and Failure. In order to find the most common [Failure Codes].[Failure] value based on a [Repair Data] record ([Repair Data] includes a field [Serial Number], which is how the junction table knows which [Repair Data] record it belongs to) would I do something like this:
reader = SELECT * FROM [Repair Data]
foreach (Record r in reader)
{
}
or is there a simpler method for achieving these results? I think I explained it correctly. I am currently not at work and I try to forget work when I'm at home . So I do not recall exactly what code I left off with. But I am quite positive I followed the "code" above.
Thanks CP.
djj55: Nice but may have a permission problem
Pete O'Hanlon: He has my permission to run it.
|
|
|
|
|
I don't know if I understand correctly your issue. I understand the issue is, that you have tables:
1. [Repaired item] ([Serial Number], [Some data about item]) - stores information about items, that are repaired (car, or whatever).
2. [Failure Codes] ([Failure Code], [Information about failure]) - stores information about failures, that can be repaired.
3. [Repair Data] ([Serial Number], [Failure Code]) - stores connection between [Repaired item] and [Failure Codes].
With the structure above you want (for the given [Serial Number]) find the failure that occurs most often.
If the above is correct, then I think you should do this in SQL using the following query:
SELECT
[Serial Number],
[Failure Code],
COUNT(*) AS [Counter]
FROM
[Failure Codes]
WHERE
[Serial Number] = @SerialNumber
GROUP BY
[Serial Number],
[Failure Code]
ORDER BY
[Counter] ASC
And you can retrieve it easily from C# without any loops.
Don't forget to rate answer, that helped you. It will allow other people find their answers faster.
|
|
|
|
|
My treeview is populated by an xml file. When I go to add a node, I'm actually altering the xml file (that's what I want). To refresh the treeview, I tried
treeSidebar.Refresh(); when that didn't work, I did
treeSidebar.Nodes.Remove(treeSidebar.Nodes[0]);
doc.Load("Subscription.xml");
treeSidebar.Nodes[0].Nodes.Add(name);
I got an error that says the file I want is being used by another process. How can I close a file so I can open it with another process?
|
|
|
|
|
XmlDoc doc = new XmlDoc();
using(FileStream fileStream = new FileStream("your file")){
doc.Load(fileStream);
}
|
|
|
|
|
Member 8069795 wrote: file I want is being used by another process
There's not much you can do about that.
Member 8069795 wrote: doc.Load("Subscription.xml");
Will close the file, so that shouldn't be the problem.
Just what is it you're trying to do? What creates the file? How many clients are trying to work with it?
|
|
|
|
|
It's an xml file that already exists, I load it once when the form loads, then when I refresh a treeview that it populates, that's the second time I want to use it.
|
|
|
|
|
If it's not shared then I don't see how another process would have it open. Maybe a threading issue? Dunno.
|
|
|
|
|
Load, parse and close.. this is some of my vb code, but it's the same principal for C#
//Load and parse tree nodes
defXmlDoc.Load(xmlPath)
TreeView1.Nodes.Clear()
//Ignore root node and add level 1
For Each node As XmlNode In defXmlDoc.DocumentElement.ChildNodes
AddNode(node, TreeView1.Nodes)
AddNodeTree(node, TreeView1.Nodes.Item(TreeView1.Nodes.Count - 1))
Next
defXmlDoc = Nothing
Private Sub AddNode(ByVal xmlNode As XmlNode, ByVal NodeCol As TreeNodeCollection)
Dim id, label, desc As String
label = xmlNode.Name
desc = ""
id = "Unknown"
If Not xmlNode.Attributes("label") Is Nothing Then
label = xmlNode.Attributes.GetNamedItem("label").Value
End If
If Not xmlNode.Attributes("description") Is Nothing Then
desc = xmlNode.Attributes.GetNamedItem("description").Value
End If
If Not xmlNode.Attributes("id") Is Nothing Then
id = xmlNode.Attributes.GetNamedItem("id").Value
If id > maxId Then maxId = id
End If
NodeCol.Add(id, label)
NodeCol(id).Tag = desc
End Sub
Private Sub AddNodeTree(ByVal xmlNode As XmlNode, ByVal treeNode As TreeNode)
Dim i As Integer
Dim xNode As XmlNode
Dim tNode As TreeNode
Dim nodeList As XmlNodeList
If (xmlNode.HasChildNodes) Then
nodeList = xmlNode.ChildNodes
For i = 0 To nodeList.Count - 1
xNode = xmlNode.ChildNodes(i)
AddNode(xNode, treeNode.Nodes)
tNode = treeNode.Nodes(i)
AddNodeTree(xNode, tNode)
Next
Else
End If
End Sub
|
|
|
|
|
I have to read an excel file and ensure the columns are in their correct order (the file is created manually and sometimes, columns are inserted in the incorrect order). I'm reading the file via microsoft jet oledb 4.0. I then insert the values into a DbDataReader.
I now have to check to see if each column is in it's propper position. So, as of now, I have the following to start with (The data reader field names are based on the column header names of the excel file):
using (DbDataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
String col1 = dr["OrderId"];
}
}
But my question is, how do I ensure dr["OrderId"] is the 1st field within the dbDataReader?
Thanks
|
|
|
|
|
You can try the other overload[^] of the DbDataReader's Item[] property:
using (DbDataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
String col1 = dr[1];
}
}
|
|
|
|
|
dr.GetOrdinal("fieldName")
|
|
|
|
|
There should never be any reason to insist that the columns are in a particular order. You're doing something wrong.
|
|
|
|
|
+5, since the order of the columns in a record could be coming from the server in a random order. And life is soo much easier if you just decide the order in the Presentation Layer - preferably having the user choose one.
OTOH, this is an Excel-sheet, and it might come without headers. In that case, only the position of the column would indicate what cell (dbfield) you're actually editing.
Things become harder if the user is allowed to move those things around. In an ideal world, each row would have a "caption" on top of the file.
Bastard Programmer from Hell
|
|
|
|
|