在运行时生成用户定义类型的参数列表(使用 C#)

发布于 2024-10-12 18:33:30 字数 3080 浏览 2 评论 0原文

作为我项目的一部分,我正在尝试构建一个 Web UI,用户将在其中选择一个方法并传递值。我的程序应该能够动态调用该方法并在运行时构建参数列表以将其传递给该方法。

我创建了一个逗号分隔的键和值对列表(字符串)。这个键/值对只不过是我的方法的参数名称和值(存储在变量中的方法名称)。示例:string params = "ID:123;姓名:Garry;地址:addressObject;AddressLine:108 Plaza Lane;City:Avenel;State:NJ;Zip:07001;"。其中 ID 和 Name 是简单的字符串变量,而 Address 是用户定义的类型。地址之后的内容即AddressLine、City、State 和Zip 是Address 对象的元素。我的方法定义是

public string GetInfo(string ID, string Name, Address addressObject)
{
  //return something;
}

我使用 DynamicProxy 动态调用存储在 sMethodName 变量中的方法(GetInfo),例如:

string sMethodName = "GetInfo";
object result = (object) proxy.CallMethod(sMethodName, arguments);

挑战是如何动态传递参数列表?到目前为止,我只能将 csv 变量中的值提取到 NamedValueCollection 中。这是代码:

public static void StoreParameterValues(string param)
{
    nvc = new NameValueCollection();
    param = param.TrimEnd(';');
    string[] parameters = param.Split(new char[] { ';' });
    foreach (string val in parameters)
    {
        string[] keyValue = val.Split(new char[] { ':' });
        nvc.Add(keyValue[0], keyValue[1]);
    }
}

..这是尝试构建参数的代码:

string methodName = "GetInfo";
DynamicProxyFactory factory = new DynamicProxyFactory("http://../myservice.svc"); 
string sContract = "";
foreach (ServiceEndpoint endpoint in factory.Endpoints)
{
    sContract = endpoint.Contract.Name;
}
DynamicProxy proxy = factory.CreateProxy(sContract);
string[] values = null;
// Create the parameter list
object[] arguments = new object[nvc.Count];
int i = -1;
foreach (string key in nvc.Keys)
{
    values = nvc.GetValues(key);
    foreach (string value in values)
    {
        arguments[++i] = value;
    }
}
object result = (object) proxy.CallMethod(methodName, arguments);

如果我有简单的基本类型,但不确定如何为任何其他用户定义类型构建逻辑,则上面的代码可以工作。如何动态创建存储在变量中的类型的对象?不确定我是否能够正确提出我的问题。我希望如此:)

编辑:01/19/2011:应用 Chris 的建议 - 使用 Reflection 而不是 ComponentModel。 我已经转换了代码以使其更通用。这现在适用于所有原始类型和自定义类型(递归)。下面的代码片段:

private object BuildParameterList(Type type)
{
    object item = new object();

    item = Activator.CreateInstance(type);            

    PropertyInfo[] propArray = type.GetProperties(BindingFlags.Public|BindingFlags.Instance);

    for (int i = 0; i < propArray.Length; i++)
    {
        PropertyInfo pi = (PropertyInfo)propArray[i];

        ////Check for custom type
        if (IsCustomType(pi.PropertyType))
        {
            object item1 = BuildParameterList(pi.PropertyType);
            pi.SetValue(item, item1, null);
        }
        else
        {
            if (property.ContainsKey(pi.Name))
            {                                               
                pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);
            }
        }
    }            
    return item;
}

但是,如果其中一个属性是 Color(我刚刚使用 Color 类型进行了测试,其他系统类型也会失败 - 我猜),那么它会在下一行失败。不确定如何处理系统类型 - 颜色或类似的东西。

pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);

As part of my project, I am trying to build a web UI where user will select a method and pass the values. My program should be able to call the method dynamically and build a parameter list on runtime to pass it to the method.

I have created a comma separated list (string) of key and value pairs. This key/value pair is nothing but the parameter name and value of my method (methodname stored in a variable). Example: string params = "ID:123;Name:Garry;Address:addressObject;AddressLine:108 Plaza Lane;City:Avenel;State:NJ;Zip:07001;". Where ID and Name are simple string varaibles while Address is user defined type. What follows after Address i.e. AddressLine, City, State and Zip is elements of Address object. And my method definition is

public string GetInfo(string ID, string Name, Address addressObject)
{
  //return something;
}

I am dynamically calling the method (GetInfo) that is stored in sMethodName variable using DynamicProxy like :

string sMethodName = "GetInfo";
object result = (object) proxy.CallMethod(sMethodName, arguments);

Challenge is how to pass the argument list dynamically? Till now I am just able to extract the values from the csv variable into NamedValueCollection. Here is the code:

public static void StoreParameterValues(string param)
{
    nvc = new NameValueCollection();
    param = param.TrimEnd(';');
    string[] parameters = param.Split(new char[] { ';' });
    foreach (string val in parameters)
    {
        string[] keyValue = val.Split(new char[] { ':' });
        nvc.Add(keyValue[0], keyValue[1]);
    }
}

..and here is the code that tries to build the parameter:

string methodName = "GetInfo";
DynamicProxyFactory factory = new DynamicProxyFactory("http://../myservice.svc"); 
string sContract = "";
foreach (ServiceEndpoint endpoint in factory.Endpoints)
{
    sContract = endpoint.Contract.Name;
}
DynamicProxy proxy = factory.CreateProxy(sContract);
string[] values = null;
// Create the parameter list
object[] arguments = new object[nvc.Count];
int i = -1;
foreach (string key in nvc.Keys)
{
    values = nvc.GetValues(key);
    foreach (string value in values)
    {
        arguments[++i] = value;
    }
}
object result = (object) proxy.CallMethod(methodName, arguments);

The above code works if I have simple primitive types but not sure how can I build the logic for any other userdefined types. How can I create a object dynamically of type stored in a variable? Not sure if I was able to put my question correctly. I hope so :)

Edit: 01/19/2011: Applied the suggestion from Chris - using Reflection instead of ComponentModel.
I have converted the code to make it more generic. This works now for all primitive and custom types (resursion). Code snippet below:

private object BuildParameterList(Type type)
{
    object item = new object();

    item = Activator.CreateInstance(type);            

    PropertyInfo[] propArray = type.GetProperties(BindingFlags.Public|BindingFlags.Instance);

    for (int i = 0; i < propArray.Length; i++)
    {
        PropertyInfo pi = (PropertyInfo)propArray[i];

        ////Check for custom type
        if (IsCustomType(pi.PropertyType))
        {
            object item1 = BuildParameterList(pi.PropertyType);
            pi.SetValue(item, item1, null);
        }
        else
        {
            if (property.ContainsKey(pi.Name))
            {                                               
                pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);
            }
        }
    }            
    return item;
}

But if one of the property is Color (I just tested with Color type, will fail with other system types aswell-i guess), then it fails at the following line. Not sure how to handle system types - Color or something similar.

pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只是在用心讲痛 2024-10-19 18:33:30

您是否无法通过检查其 ParameterInfo 找到该方法所需的类型:

endpoint.Contract.ContractType.GetMethod(methodName).GetParameters();

然后使用以下方法实例化自定义类型:

Activator.CreateInstance(parameterType);

Can you not find what types are expected by the method, by inspecting its ParameterInfos:

endpoint.Contract.ContractType.GetMethod(methodName).GetParameters();

and then instantiating the custom types using:

Activator.CreateInstance(parameterType);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文