3

C# 小技巧 - 使用匿名型別傳遞多參數

 2 years ago
source link: https://blog.darkthread.net/blog/conv-object-to-dictionary/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

C# 小技巧 - 使用匿名型別傳遞多參數

calendar.svg 2021-11-02 09:15 PM comment.svg 2 eye.svg 1,524

專案有個 HTTP POST 呼叫特定 URL 的共用函式需求,參數採完全彈性,給什麼就組什麼,直接轉成 p1=...&p2=...&p3=... application/x-www-form-urlencode 格式送出。

若用 .NET 寫,最省事的做法是將參數轉成 NameValueCollection 傳給 WebClient.UploadValues(),全靠現成元件,輕鬆秒殺。(延伸閱讀:利用 WebClient 類別模擬 HTTP POST 表單送出的注意事項 by 保哥)

對呼叫端而言,用 Dictionary<string, string> 比 NameValueCollection 順手,因此我的第一個版本長這樣:

static string url = "http://localhost/aspnet/post/";
static void ClassicPostRequest(Dictionary<string, string> data)
{
    var wc = new WebClient();
    var nvc = new NameValueCollection();
    foreach (var kv in data)
        nvc[kv.Key] = kv.Value;
    var resp = wc.UploadValues(url, nvc);
    Console.WriteLine(Encoding.UTF8.GetString(resp));
}
static void Main(string[] args)
{
    var guid = Guid.NewGuid();
    var time = DateTime.Now.ToString("yyyy-MM-dd");

    ClassicPostRequest(new Dictionary<string, string>
    {
        ["num"] = "123",
        ["letters"] = "ABC",
        ["time"] = time,
        ["guid"] = guid.ToString()
    });
    Console.Read();
}

如果別太挑剔,這個版本已經蠻好用。

BUT! Dapper 寫多用慣 new { prop1, prop2, prop3 = ... } 傳參數的簡潔寫法,new Dictionary<string, string> { ["prop1"] = prop1Value ... } 怎麼看怎麼 Low,大概就是所謂「曾經滄海難為水」吧。

cn.Query<ResultItem>("SELECT * FROM Items WHERE Col1 = @p1 AND Col2 = @p2 AND Col3 IN @array", 
    new { p1, p2, array = new string[] { "A", "B" } });

何不仿效 Dapper,也用自訂匿名物件彈性指定參數呢?試寫了一下,System.Reflection 加 LINQ 三兩下搞定:

static string url = "http://localhost/aspnet/post/";

static void NewPostRequest(object args) {
    var wc = new WebClient();
    var resp = wc.UploadValues(url, AnonymousTypeToNameValueCollection(args));
    Console.WriteLine(Encoding.UTF8.GetString(resp));
}

static NameValueCollection AnonymousTypeToNameValueCollection(object args)
{
    var postData = new NameValueCollection();
    args.GetType().GetProperties()
    .ToList()
    .ForEach(p =>
    {
        var valObj = p.GetValue(args);
        //TODO 視需要自訂物件轉字串邏輯
        var valStr = p.PropertyType == typeof(DateTime) ?
            ((DateTime)valObj).ToString("yyyy-MM-dd HH:mm:ss") :
            valObj.ToString();
        postData.Add(p.Name, valStr);
    });
    return postData;
}

static void Main(string[] args)
{
    var guid = Guid.NewGuid();
    var time = DateTime.Now.ToString("yyyy-MM-dd");

    NewPostRequest(new 
    {
        num = "123",
        letters = "ABC",
        time,
        guid
    });
    Console.Read();
}

是不是優雅多了?

  • Posted in
  • C#
and has 2 comments

Comments

# 2021-11-03 06:26 AM by 凱大

static void NewPostRequest<T>(T args, Func<T, NameValueCollection> func) { var wc = new WebClient(); var resp = wc.UploadValues(url, func(args)); Console.WriteLine(Encoding.UTF8.GetString(resp)); } NewPostRequest(new { num = "123", letters = "ABC", time, guid }, obj => /* 在這裡 obj 的型別為前面的匿名型別 可以不用 reflection 就存取 property */ );

Post a comment

Comment
Name Captcha 89 - 74 =

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK