using OpenTap.Addin.Annotation; using OpenTap.Addin.Entity; using System; using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.ComponentModel; using System.Dynamic; using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Serialization; namespace OpenTap.Addin { public enum TestVariableType { String = 0, Int = 1, Double = 2, Bool = 3, Container = 8, Refrence = 9 } public class NullVariable : DynamicObject { private string _____name_____; public NullVariable(string name) { _____name_____ = name; } public override bool TryGetMember(GetMemberBinder binder, out object result) { throw new ArgumentException($"参数 {_____name_____} 不存在"); } public override bool TrySetMember(SetMemberBinder binder, object value) { throw new ArgumentException($"参数 {_____name_____} 不存在"); } public object this[int index] { get { throw new ArgumentException($"参数 {_____name_____} 不存在"); } set { throw new ArgumentException($"参数 {_____name_____} 不存在"); } } public static bool operator ==(NullVariable v1, object v2) { if (v2 is NullVariable) return true; return v2 == null; } public static bool operator !=(NullVariable v1, object v2) { if (v2 is NullVariable vv2) return v1 == vv2; return v2 != null; } public override string ToString() { return "NULL"; } public override bool Equals(object obj) { return obj is NullVariable variable; } public override int GetHashCode() { throw new NullReferenceException(); } } public class TestVariable : DynamicObject, INotifyPropertyChanged { #region ... public event PropertyChangedEventHandler PropertyChanged; protected void Set([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } protected void Set(ref T old, T @new, [CallerMemberName] string propertyName = null) { old = @new; if (propertyName != null) { Set(propertyName); } } #endregion private bool nameCanEdit = true; [XmlIgnore] public bool NameCanEdit { get => nameCanEdit; set { Set(ref nameCanEdit, value); } } private string name; [DataGridCol("名称", "*", true)] public string Name { get => name; set { Set(ref name, value); Set(nameof(Title)); } } private string contextName; [XmlIgnore] public string ContextName { get => contextName; set { Set(ref contextName, value); Set(nameof(Title)); } } [XmlIgnore] public string Title { get { if (string.IsNullOrEmpty(ContextName)) return Name; return $"{Name} ({ContextName})"; } set { Set(ref name, value); Set(nameof(Title)); } } public bool IsArray { get; set; } private TestVariableType type; [DataGridCol("类型", "*", true)] public TestVariableType Type { get => type; set { Set(ref type, value); } } [DataGridCol("值", "*", false, true)] public string Value { get; set; } private ObservableCollection children = new ObservableCollection(); public ObservableCollection Children { get => children; set { Set(ref children, value); } } public override bool TryGetMember(GetMemberBinder binder, out object result) { result = null; string name = binder.Name; var pInfo = typeof(TestVariable).GetProperty(name); if (pInfo == null) { var child = Children.FirstOrDefault(c => c.Name == name); if (child == null) { result = new NullVariable($"{this.Name}.{name}"); return true; } if (child.IsArray || child.Type == TestVariableType.Container) { result = child; } else { result = child.GetValue(); } return true; } else { result = pInfo.GetValue(this); return true; } } public object this[int index] { get { if (!IsArray) { throw new Exception(); } return Children[index].GetValue(); } set { if (!IsArray) { throw new Exception(); } Children[index].Value = value.ToString(); } } public override bool TrySetMember(SetMemberBinder binder, object value) { string name = binder.Name; var pInfo = typeof(TestVariable).GetProperty(name); if (pInfo == null) { var child = Children.FirstOrDefault(c => c.Name == name); if (child == null) { if (Type != TestVariableType.Container) { return false; } child = new TestVariable { Name = name }; Children.Add(child); } child.Type = FormatType(value.GetType()); child.Value = value.ToString(); return true; } else { pInfo.SetValue(this, value); return true; } } public object GetValue() { if (Type == TestVariableType.Int) { return new NumberData(Value); } else if (Type == TestVariableType.Double) { return new NumberData(Value); } else if (Type == TestVariableType.Bool) { if (bool.TryParse(Value, out bool boolValue)) return boolValue; } else if (Type == TestVariableType.String) { return Value; } return null; } public RuntimeVariable ToRuntime(TestPlanRun run) { if (IsArray) { switch (Type) { case TestVariableType.String: return new RuntimeVariable(run, Name, Children.Select(e => e.GetValue()).ToArray()); case TestVariableType.Int: return new RuntimeVariable(run, Name, Children.Select(e => e.GetValue()).ToArray()); case TestVariableType.Double: return new RuntimeVariable(run, Name, Children.Select(e => e.GetValue()).ToArray()); case TestVariableType.Bool: return new RuntimeVariable(run, Name, Children.Select(e => e.GetValue()).ToArray()); case TestVariableType.Container: return new RuntimeVariable(run, Name, Children.Select(e => e.ToRuntime(run)).ToArray()); case TestVariableType.Refrence: return new RuntimeVariable(run, Name, Children.Select(e => e.GetValue()).ToArray()); } } else { switch (Type) { case TestVariableType.String: return new RuntimeVariable(run, Name, Value); case TestVariableType.Int: return new RuntimeVariable(run, Name, GetValue()); case TestVariableType.Double: return new RuntimeVariable(run, Name, GetValue()); case TestVariableType.Bool: return new RuntimeVariable(run, Name, GetValue()); case TestVariableType.Container: return new RuntimeVariable(run, Name, new ConcurrentDictionary (Children.Select(e => e.ToRuntime(run)).ToDictionary(v => v.__name___, v => v))); case TestVariableType.Refrence: return new RuntimeVariable(run, Name, null); } } return null; } public object GetValue__() { if (Type == TestVariableType.Int) { if (int.TryParse(Value, out int intValue)) return intValue; } else if (Type == TestVariableType.Double) { if (double.TryParse(Value, out double doubleValue)) return doubleValue; } else if (Type == TestVariableType.Bool) { if (bool.TryParse(Value, out bool boolValue)) return boolValue; } else if (Type == TestVariableType.String) { return Value; } return null; } //public RuntimeVariable ToRuntime___() //{ // if (IsArray) // { // switch (Type) // { // case TestVariableType.String: // return new RuntimeVariable // { // Name = Name, // Type = typeof(string[]), // TypeName = "string[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Int: // return new RuntimeVariable // { // Name = Name, // Type = typeof(int[]), // TypeName = "int[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Double: // return new RuntimeVariable // { // Name = Name, // Type = typeof(double[]), // TypeName = "double[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Bool: // return new RuntimeVariable // { // Name = Name, // Type = typeof(bool[]), // TypeName = "bool[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Container: // return new RuntimeVariable // { // Name = Name, // Type = typeof(object[]), // TypeName = "Container[]", // data = new VariableContext(Name, new ConcurrentDictionary // (Children.Select(e => e.ToRuntime()).ToDictionary(v => v.Name, v => v))) // }; // } // } // else // { // switch (Type) // { // case TestVariableType.String: // return new RuntimeVariable // { // Name = Name, // Type = typeof(string), // TypeName = "string", // data = Value // }; // case TestVariableType.Int: // return new RuntimeVariable // { // Name = Name, // Type = typeof(int), // TypeName = "int", // data = int.Parse(Value) // }; // case TestVariableType.Double: // return new RuntimeVariable // { // Name = Name, // Type = typeof(double), // TypeName = "double", // data = double.Parse(Value) // }; // case TestVariableType.Bool: // return new RuntimeVariable // { // Name = Name, // Type = typeof(bool), // TypeName = "bool", // data = bool.Parse(Value) // }; // case TestVariableType.Container: // return new RuntimeVariable // { // Name = Name, // Type = typeof(object[]), // TypeName = "object", // data = new VariableContext(Name, new ConcurrentDictionary // (Children.Select(e => e.ToRuntime()).ToDictionary(v => v.Name, v => v))) // }; // } // } // return null; //} //public RuntimeContext ToRuntime2() //{ // if (IsArray) // { // var // switch (Type) // { // case TestVariableType.String: // return new RuntimeContext // { // Name = Name, // Type = typeof(string[]), // TypeName = "string[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Int: // return new RuntimeVariable // { // Name = Name, // Type = typeof(int[]), // TypeName = "int[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Double: // return new RuntimeVariable // { // Name = Name, // Type = typeof(double[]), // TypeName = "double[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Bool: // return new RuntimeVariable // { // Name = Name, // Type = typeof(bool[]), // TypeName = "bool[]", // data = Children.Select(e => e.GetValue()).ToArray() // }; // case TestVariableType.Container: // return new RuntimeVariable // { // Name = Name, // Type = typeof(object[]), // TypeName = "Container[]", // data = new VariableContext(new ConcurrentDictionary // (Children.Select(e => e.ToRuntime()).ToDictionary(v => v.Name, v => v))) // }; // } // } // else // { // switch (Type) // { // case TestVariableType.String: // return new RuntimeVariable // { // Name = Name, // Type = typeof(string), // TypeName = "string", // data = Value // }; // case TestVariableType.Int: // return new RuntimeVariable // { // Name = Name, // Type = typeof(int), // TypeName = "int", // data = int.Parse(Value) // }; // case TestVariableType.Double: // return new RuntimeVariable // { // Name = Name, // Type = typeof(double), // TypeName = "double", // data = double.Parse(Value) // }; // case TestVariableType.Bool: // return new RuntimeVariable // { // Name = Name, // Type = typeof(bool), // TypeName = "bool", // data = bool.Parse(Value) // }; // case TestVariableType.Container: // return new RuntimeVariable // { // Name = Name, // Type = typeof(object[]), // TypeName = "object", // data = new VariableContext(new ConcurrentDictionary // (Children.Select(e => e.ToRuntime()).ToDictionary(v => v.Name, v => v))) // }; // } // } // return null; //} public static TestVariableType FormatType(Type type) { if (type == typeof(string)) { return TestVariableType.String; } if (type == typeof(int)) { return TestVariableType.Int; } if (type == typeof(double)) { return TestVariableType.Double; } if (type == typeof(bool)) { return TestVariableType.Bool; } return TestVariableType.Refrence; } public static string DefaultValue(TestVariableType type) { switch (type) { case TestVariableType.String: return string.Empty; case TestVariableType.Int: return "0"; case TestVariableType.Double: return "0"; case TestVariableType.Bool: return "False"; default: return null; } } } }