我试图从PLC获取一些值(每个值都有一个名称和一个int值)并在PC上保存它们以备份。
所以我得到了一个名称和int的结构
public struct sValues
{
public string ObjectName;
public int Value;
}
由于我需要存储许多值,因此我还有一个包含所有这些值的类。
public class MemMainS
{
public sValues svMode;
public sValues svFreqOrBal;
(...)
}
和班级列表
MemMainS mainCurrent = new MemMainS();
public List<MemMainS> TestList = new List<MemMainS>();
我也有一些测试值
private void SetTest()
{
mainCurrent.svMode.ObjectName = "Obj1.Addr1";
mainCurrent.svMode.Value = 1;
mainCurrent.svFreqOrBal.ObjectName = "Obj2.Addr2";
mainCurrent.svFreqOrBal.Value = 2;
}
当我尝试使用foreach从List中获取数据时,只有当我告诉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++;
}
}
我错过了一些我没有想过的东西吗?或者甚至可能吗?
如果我尝试 sv = TestList.ElemntAt(j); VS编译器告诉我类型不同,但类型是sValues,因为sv是。
无法隐式转换类型&#39; WinFormServer.Memory.MemMainS&#39;至 &#39; WinFormServer.Memory.sValues&#39;
答案 0 :(得分:1)
列出List<MemMainS>
;因此列表的第j个元素是MemMainS
。您正尝试将其分配给sv
,sValues
值。这默认不起作用;你可以添加隐式转换运算符,但你真的可能不应该。但是如果你搜索“C#重载隐式转换运算符”它会告诉你如何。只访问第j个元素的.svMode
成员要容易得多。
答案 1 :(得分:1)
我建议利用.Net中的索引器属性来修改MemMainS
类,使其行为类似于Dictionary集合,如下所示:
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;} };
// (...)
}
这会让你像这样重写循环以避免反思:
foreach (var mv in TestList)
{
foreach(string item in mv.Keys)
{
sValues sv = mv[item];
}
}
或者像这样:
foreach(var mv in TestList)
{
foreach(sValues sv in mv)
{
//...
}
}
这里的问题是我们不知道我们在这些循环中查看的 sValue属性。我们有ObjectName
地址,但没有属性名称。看起来这些属性名称应该包含在struct数据中。您有一个属性名称,如svFreqOrBal
,它将具有1:1映射到ObjectName或地址,如Obj2.Addr2
。没有理由不将其作为结构的一部分。
虽然我在这里,但我建议使用简单的不可变模式来定义结构:
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;
}
}
(当然,如上所述可能添加了name属性。)
最后,在评论中看到您有超过1000个潜在的不同PLC值,您可能想要完全放弃MemMainS
中的命名属性,并且只使用Dictionary + indexer。当然,这会花费您一些编译时的安全性,但您可以通过获取有效PLC值名称的列表或字符串[]来弥补其中的一部分,您可以在索引器中进行检查以进行验证。