33

C#では、次のようなことができます。

var a = new {name = "cow", sound = "moooo", omg = "wtfbbq"};

Pythonでは、次のようなことができます。

a = t(name = "cow", sound = "moooo", omg = "wtfbbq")

もちろんデフォルトではありませんが、クラスを実装するのは簡単ですtそれができます。私がPythonで作業していたとき、私はまさにそれをしました、そしてそれはあなたがインデックスではなく名前でコンポーネントにアクセスすることができるようにしたい小さな使い捨てコンテナのために信じられないほど便利であると思いました。

それ以外の細部を除けば、それらは基本的に彼らが仕えるニッチのタプルと同じです。

特に、私は今、このC#コードを見ています。

routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

それはF#相当です

type Route = { 
    controller : string
    action : string
    id : UrlParameter }

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    { controller = "Home"; action = "Index"; id = UrlParameter.Optional } // Parameter defaults
  )

どちらかといえば冗長で反復的で、どちらかといえば面倒です。 F#のこの種の構文にどれだけ近づくことができますか。それがそれが私にこのようなコードを乾燥させるのに役に立つ何かを与えるだろうという意味なら今私はいくつかのフープ(燃えるようなフープさえ!)を飛び越えても構わない。


  • 匿名型がc#のタプルではないことを言及するだけで、Tupleクラスがあります。 - Ben Robinson

4 답변


24

やりやすい

let route = routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}" // URL with parameters
    )
route.Defaults.Add("controller", "Home")
route.Defaults.Add("action", "Index")

または

[ "controller", "Home"
  "action", "Index" ]
|> List.iter route.Defaults.Add

F#では、匿名型を受け入れるオーバーロードを呼び出すことは避けますFSharpListC#から。これらは言語固有の機能です。通常、言語に依存しない過負荷/回避策があります。

編集

ドキュメントを見ただけです - これを実行するもう1つの方法があります

let inline (=>) a b = a, box b

let defaults = dict [
  "controller" => "Home"
  "action"     => "Index" 
]
route.Defaults <- RouteValueDictionary(defaults)


  • +1これは間違いなく良いです。のためのより賢明な過負荷があることを私は知りませんでしたAdd - 私は私のASP.NET MVCサンプルでもそれを使うべきです! - Tomas Petricek
  • 再:RouteValueDictionaryを使用して。予想される辞書タイプがIDictionary< string、obj>であるため、これはコンパイルされますが、動作しません。実行時には「obj」のボックスが解除されるので、作成時に最初にボックスに入れる必要があります。代わりに、 "dict [(" controller "、box" Home ");(" action "、box" Index ")]を使用してください。これにより、混合型のデフォルトも有効になります。 ("ユーザー"ボックスnull)、(" ID"、ボックスUrlParameter.Optional)。 - Stephen Hosking
  • @ Javaman59:おっと、値をボックスに入れるのを忘れていました。一定。ありがとう。 - Daniel
  • @ダニエル。よくやった。 (=>)演算子が好きです。もっと読みやすくします。 - Stephen Hosking

18

F#で "匿名レコード"を作成することはできません。型を使用するときは、匿名でタプルを使用せずにラベルを付けることも、事前に宣言してラベルを付けるレコードを使用することもできます。

// Creating an anonymous tuple
let route = ("Home", "Index", UrlParameter.Optional)

// Declaration and creating of a record with named fields
type Route = { controller : string; action : string; id : UrlParameter } 
let route = { controller = "Home"; action = "Index"; id = UrlParameter.Optional } 

技術的には、匿名レコードの問題はそれらが実際のクラスとして定義されなければならないということです。どこかに(.NETランタイムには型が必要です)しかし、コンパイラがそれらをすべてのアセンブリに入れると、同じメンバを持つ2つの無名レコードが異なるアセンブリで定義されている場合、それらは異なる型になる可能性があります。

正直に言って、あなたが投稿した例はASP.NETの設計上の不適切な決定にすぎないと思います - それは設計されていない何かをするために特定のC#機能を誤用しているためです。それほど悪くないかもしれませんこのしかし、それはまだ変です。このライブラリはC#の匿名型を取りますが、辞書として使用します(つまり、指定する必要があるプロパティが動的であるため、キーと値のペアを作成するための良い方法として使用します)。

そのため、F#からASP.NETを使用している場合は、レコードを作成する必要がない場合に代替アプローチを使用する方がおそらく簡単です。それを書く方法)。


  • @カーク:アンIDictionaryより良い選択のようです。 F#ではそれはdict ["controller", "Home"; "action", "Index"] - とても自然 - Daniel
  • 私はそれが実際には簡潔でも明確でもないと思います。new Dictionary<string, object> { { "controller", "Home" }, { "action", "Index" } }new { controller = "Home", action = "Index" }(そして、C#ではもっと悪くならない解決策を具体的に求めていました) - Kirk Woll
  • 言わないでおくIDictionaryC#ではより明確または短いですが、いくつかの言語がCLRをターゲットにしていることを考えると、これはより良いアプローチ(幸せな媒体)です。匿名型はC#固有のものです。 - Daniel
  • 重要なのは、ASP.NETが(C#ライブラリではなく).NETライブラリである場合、人々が使用しようとしている言語について単純に仮定するべきではないということです。プロパティを持つクラスを使用して辞書を表現することは、純粋な.NETの観点からは非常に愚かに思えます。 - Tomas Petricek
  • @Kirk - C#でも、発見可能性など、このアプローチにはまだ問題があります。のdefaultsパラメータの型はobject「デフォルトルート値を含むオブジェクト」の説明付き。呼び出し側としては、ライブラリで使用されている非常に慣用的なスタイルの例を見たことがない限り、これはまったく不可解です。私には、これは、F#にはないC#機能の積極的な使用ではなく、C#が簡潔なコレクションリテラルをサポートできないことに対する回避策の兆候です。 - kvb

11

OPは匿名型の最良の使用法を説明していません。 LINQを使って任意のクラスにマッピングするときに最もよく使われます。例えば:

var results = context.Students
              .Where(x => x.CourseID = 12)
              .Select(x => new { 
                 StudentID = x.ID, 
                 Name = x.Forename + " " + x.Surname
              });

これは新しいレコードタイプを定義することで実現できることを私は知っていますが、コードを管理する場所は2つあります。(1)レコードタイプの定義(2)使用した場所。

代わりにタプルで実行することもできますが、個々のフィールドにアクセスするには分解構文を使用する必要があります。(studentId, name)ずっと。タプルに5つのアイテムがあると、これは扱いにくくなります。入力したいxそしてドットを打って、どのフィールドが利用可能であるかをインテリセンスに教えてもらってください。


1

これがデフォルトのWebプロジェクトのルート設定です。

module RouteConfig =

    open System.Web.Mvc
    open System.Web.Routing

    let registerRoutes (routes: RouteCollection) =

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

        /// create a pair, boxing the second item
        let inline (=>) a b = a, box b

        /// set the Defaults property from a given dictionary
        let setDefaults defaultDict (route : Route) =  
            route.Defaults <- RouteValueDictionary(defaultDict)

        routes.MapRoute(name="Default", url="{controller}/{action}/{id}")
        |> setDefaults (dict ["controller" => "Home" 
                              "action" => "Index" 
                              "id" => UrlParameter.Optional])

リンクされた質問


関連する質問

最近の質問