Reputation: 19
I'm trying to get some values from a PLC (each value has a name and a int value) and save them for backup reasons on a PC.
So i got a Struct for the name and the int
public struct sValues
{
public string ObjectName;
public int Value;
}
As there are many values that I need to store I also got a class with all of them.
public class MemMainS
{
public sValues svMode;
public sValues svFreqOrBal;
(...)
}
And a List of the Class
MemMainS mainCurrent = new MemMainS();
public List<MemMainS> TestList = new List<MemMainS>();
I also got some test values
private void SetTest()
{
mainCurrent.svMode.ObjectName = "Obj1.Addr1";
mainCurrent.svMode.Value = 1;
mainCurrent.svFreqOrBal.ObjectName = "Obj2.Addr2";
mainCurrent.svFreqOrBal.Value = 2;
}
When I try to get the data from the List with a foreach it's only possible if I tell the exact element of the List
foreach (var mv in TestList)
{
FieldInfo[] listFields = mv.GetType().GetFields(BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance);
int j = 0;
foreach (FieldInfo lf in listFields)
{
FieldInfo[] classFields = lf.FieldType.GetFields(BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance);
foreach(FieldInfo cf in classFields)
{
sValues sv;
//sv = TestList.ElementAt(j);//Possible to get it working like this?
sv = TestList.ElementAt(j).svMode;//Works for just svMode
//Output:
//Obj1.Addr1
//1
}
j++;
}
}
Am I missing something that I didn't thought of yet? Or is it even possible?
If I try sv = TestList.ElemntAt(j); VS compiler tells me that the type is not the same but the type is of sValues as sv is.
Cannot implicitly convert type 'WinFormServer.Memory.MemMainS' to 'WinFormServer.Memory.sValues'
Upvotes: 0
Views: 146
Reputation: 415630
I suggest taking advantage of the indexer properties in .Net to modify the MemMainS
class to behave just a little like a Dictionary collection, like this:
public class MemMainS
{
private Dictionary<string, sValues> data = new Dictionary<string, sValues>();
public ICollection<string> Keys {get {return data.Keys;} }
public Dictionary<string, sValues>.ValueCollection.Enumerator GetEnumerator()
{
return data.Values.GetEnumerator();
}
public sValues this[string valueName]
{
get
{
if (data.ContainsKey(valueName)) return data[valueName];
return default(sValues); // could opt to throw an exception here instead
}
set
{
data[valueName] = value;
}
}
public sValues svMode {get {return data["svMode"]; } set {data["svMode"] = value;} }
public sValues svFreqOrBal {get {return data["svFreqOrBal "]; } set {data["svFreqOrBal "] = value;} };
// (...)
}
That will let you re-write the loop like this to avoid reflection:
foreach (var mv in TestList)
{
foreach(string item in mv.Keys)
{
sValues sv = mv[item];
}
}
Or like this:
foreach(var mv in TestList)
{
foreach(sValues sv in mv)
{
//...
}
}
The problem here is we don't know which sValue property we're looking at in those loops. We have the ObjectName
address, but not the property name. It seems like those property names should be included in the struct data. You have a property name, like svFreqOrBal
, that will have a 1:1 mapping to a ObjectName or address like Obj2.Addr2
. There's no reason not to include that as part of the struct.
While I'm here, I suggest defining the struct using a simple immutable pattern this way:
public struct sValues
{
public string ObjectName {get;private set;}
public int Value {get; private set;}
public sValues(string objectName, int Value)
{
ObjectName = objectName;
this.Value = Value;
}
}
(Of course, with the potential addition of the name property as suggested above).
Finally, seeing in the comments you have more than 1000 potential different PLC values, you may want to forgo the named properties in MemMainS
entirely, and only use the Dictionary + indexer. Of course, this costs you some compile-time safety, but you can make up for some of this by getting a list or string[] of your valid PLC value names you can check against in the indexer for validation.
Upvotes: 1
Reputation: 1062550
You list a List<MemMainS>
; therefore the j'th element of the list is a MemMainS
. You are trying to assign it to sv
, a sValues
value. That doesn't work by default; you can add an implicit conversion operator, but you really probably shouldn't. But if you search "C# overload implicit conversion operator" it'll show you how. It is much easier to just access the .svMode
member of the j'th element.
Upvotes: 1