I was a bit impatient (and lazy) and asked ChatGPT (AI). Together we came up with the following solution:
private void btnTestMethod_Click(object sender, EventArgs e)
{
InvokeMethod();
}
private void InvokeMethod()
{
try
{
if (_selectedClass != null && !string.IsNullOrEmpty(_selectedMethod))
{
ConstructorInfo classConstructor = _selectedClass.GetConstructor(Type.EmptyTypes);
object classObject = classConstructor.Invoke(new object[] { });
List<object> parameterValues = new List<object>();
List<Type> parameterTypes = new List<Type>();
for (int idx = 0; idx < pnlParameters.Controls.Count; idx++)
{
string parameterName = pnlParameters.Controls[idx].Name;
var parameter = _selectedParameters.FirstOrDefault(param => param.Name.Equals(parameterName));
if (parameter != null)
{
object parameterObject;
parameterTypes.Add(parameter.ParameterType);
switch (Type.GetTypeCode(parameter.ParameterType))
{
case TypeCode.String:
parameterObject = pnlParameters.Controls[idx].Text;
break;
case TypeCode.Int16:
if (short.TryParse(pnlParameters.Controls[idx].Text, out short shortValue))
parameterObject = shortValue;
else
throw new ArgumentException("Invalid Int16 value for parameter: " + parameter.Name);
break;
case TypeCode.Int32:
if (int.TryParse(pnlParameters.Controls[idx].Text, out int intValue))
parameterObject = intValue;
else
throw new ArgumentException("Invalid Int32 value for parameter: " + parameter.Name);
break;
case TypeCode.Int64:
if (long.TryParse(pnlParameters.Controls[idx].Text, out long longValue))
parameterObject = longValue;
else
throw new ArgumentException("Invalid Int64 value for parameter: " + parameter.Name);
break;
case TypeCode.Boolean:
switch (pnlParameters.Controls[idx])
{
case CheckBox checkBox:
parameterObject = checkBox.Checked;
break;
case TextBox textBox:
default:
if (bool.TryParse(pnlParameters.Controls[idx].Text, out bool boolValue))
parameterObject = boolValue;
else
throw new ArgumentException("Invalid Boolean value for parameter: " + parameter.Name);
break;
}
break;
case TypeCode.Object:
if (parameter.ParameterType.IsGenericType &&
parameter.ParameterType.GetGenericTypeDefinition() == typeof(List<>))
{
Type elementType = parameter.ParameterType.GetGenericArguments()[0];
if (pnlParameters.Controls[idx] is DataGridView dataGridView)
{
IList listObject = (IList)Activator.CreateInstance(parameter.ParameterType);
foreach (DataGridViewRow row in dataGridView.Rows)
{
if (!row.IsNewRow)
{
object elementObject = Activator.CreateInstance(elementType);
foreach (DataGridViewCell cell in row.Cells)
{
string columnName = cell.OwningColumn.Name;
PropertyInfo property = elementType.GetProperty(columnName);
if (property != null)
{
object cellValue = cell.Value;
switch (Type.GetTypeCode(property.PropertyType))
{
case TypeCode.String:
property.SetValue(elementObject, cellValue);
break;
case TypeCode.Int16:
if (short.TryParse(cellValue.ToString(), out short shortCellValue))
property.SetValue(elementObject, shortCellValue);
else
throw new ArgumentException("Invalid Int16 value for parameter: " + parameter.Name);
break;
case TypeCode.Int32:
if (int.TryParse(cellValue.ToString(), out int intCellValue))
property.SetValue(elementObject, intCellValue);
else
throw new ArgumentException("Invalid Int32 value for parameter: " + parameter.Name);
break;
case TypeCode.Int64:
if (long.TryParse(cellValue.ToString(), out long lngCellValue))
property.SetValue(elementObject, lngCellValue);
else
throw new ArgumentException("Invalid Int64 value for parameter: " + parameter.Name);
break;
case TypeCode.Boolean:
if (bool.TryParse(cellValue.ToString(), out bool blnCellValue))
property.SetValue(elementObject, blnCellValue);
else
throw new ArgumentException("Invalid Boolean value for parameter: " + parameter.Name);
break;
case TypeCode.Object:
if (property.PropertyType.IsEnum)
{
if (cellValue != null)
{
object enumValue = Enum.Parse(property.PropertyType, cellValue.ToString());
property.SetValue(elementObject, enumValue);
}
else
{
throw new ArgumentException("Invalid Enum value for parameter: " + parameter.Name);
}
}
else
{
property.SetValue(elementObject, cellValue);
}
break;
default:
property.SetValue(elementObject, cellValue);
break;
}
}
}
listObject.Add(elementObject);
}
}
parameterObject = listObject;
}
else
{
throw new ArgumentException("Invalid control type for List parameter: " + parameter.Name);
}
}
else
{
throw new ArgumentException("Unsupported object type for parameter: " + parameter.Name);
}
break;
default:
throw new ArgumentException("Unsupported parameter type: " + parameter.ParameterType.Name);
}
parameterValues.Add(parameterObject);
}
}
MethodInfo classMethod = _selectedClass.GetMethod(_selectedMethod, parameterTypes.ToArray());
object result = classMethod.Invoke(classObject, parameterValues.ToArray());
DisplayResults(result);
}
}
catch (Exception ex)
{
ShowErrorMessage(ex);
}
}
private void DisplayResults(object result)
{
pnlResults.Controls.Clear();
Type resultType = result.GetType();
switch (result)
{
case null:
Label lblNoResults = new Label();
lblNoResults.Text = "No results available.";
lblNoResults.Dock = DockStyle.Fill;
pnlResults.Controls.Add(lblNoResults);
break;
case string strResult:
TextBox txtResult = new TextBox();
txtResult.Text = strResult;
txtResult.ReadOnly = true;
txtResult.Dock = DockStyle.Fill;
pnlResults.Controls.Add(txtResult);
break;
case ICollection collectionResult:
if (resultType.IsGenericType)
{
TreeView tvCollection = XmlDocumentToTreeView(result);
tvCollection.Dock = DockStyle.Fill;
pnlResults.Controls.Add(tvCollection);
}
else
{
ListBox lstResult = new ListBox();
lstResult.Items.AddRange(collectionResult.Cast<object>().ToArray());
lstResult.Dock = DockStyle.Fill;
pnlResults.Controls.Add(lstResult);
}
break;
case DataTable dataTableResult:
DataGridView dgvResult = new DataGridView();
dgvResult.DataSource = dataTableResult;
dgvResult.Dock = DockStyle.Fill;
pnlResults.Controls.Add(dgvResult);
break;
case TreeNode treeNodeResult:
TreeView tvResult = new TreeView();
tvResult.Nodes.Add(treeNodeResult);
tvResult.Dock = DockStyle.Fill;
pnlResults.Controls.Add(tvResult);
break;
default:
Control resultControl = CreateObjectControl(result);
if (resultControl != null)
{
resultControl.Dock = DockStyle.Fill;
pnlResults.Controls.Add(resultControl);
}
else
{
Label lblUnsupported = new Label();
lblUnsupported.Text = "Result type not supported for display.";
lblUnsupported.Dock = DockStyle.Fill;
pnlResults.Controls.Add(lblUnsupported);
}
break;
}
}
private Control CreateObjectControl(object result)
{
Type resultType = result.GetType();
if (resultType.IsClass && !resultType.IsPrimitive && !resultType.IsArray)
{
Panel resultPanel = new Panel();
resultPanel.AutoScroll = true;
PropertyInfo[] properties = resultType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
int yOffset = 0;
foreach (PropertyInfo property in properties)
{
Label lblPropertyName = new Label();
lblPropertyName.Text = property.Name;
lblPropertyName.Location = new Point(0, yOffset);
resultPanel.Controls.Add(lblPropertyName);
TextBox txtPropertyValue = new TextBox();
object propertyValue = property.GetValue(result);
txtPropertyValue.Text = propertyValue?.ToString() ?? "null";
txtPropertyValue.Location = new Point(100, yOffset);
txtPropertyValue.ReadOnly = true;
resultPanel.Controls.Add(txtPropertyValue);
yOffset += 30;
}
return resultPanel;
}
return XmlDocumentToTreeView(result);
}
private TreeView XmlDocumentToTreeView(object result)
{
TreeView tvResult = new TreeView();
tvResult.Dock = DockStyle.Fill;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(SerializeToXml(result));
TreeNode rootNode = CreateTreeNode(xmlDoc.DocumentElement);
tvResult.Nodes.Add(rootNode);
return tvResult;
}
public string SerializeToXml(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, obj);
return writer.ToString();
}
}
private TreeNode CreateTreeNode(XmlNode xmlNode)
{
TreeNode treeNode = new TreeNode(xmlNode.Name);
foreach (XmlNode childNode in xmlNode.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
TreeNode childTreeNode = CreateTreeNode(childNode);
treeNode.Nodes.Add(childTreeNode);
}
else if (childNode.NodeType == XmlNodeType.Text)
{
treeNode.Nodes.Add(childNode.InnerText);
}
}
return treeNode;
}