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#中的这种语法?我现在不介意跳过一些箍(甚至是火红的箍!),如果这意味着它会给我一些有用的东西来干掉像这样的代码。
答案 0 :(得分: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#中,我会避免调用接受匿名类型的重载,因为我会避免调用从C#接受FSharpList
的F#方法。这些是特定于语言的功能。通常可以使用与语言无关的重载/解决方法。
只看文档 - 这是另一种方法
let inline (=>) a b = a, box b
let defaults = dict [
"controller" => "Home"
"action" => "Index"
]
route.Defaults <- RouteValueDictionary(defaults)
答案 1 :(得分: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运行时需要一种类型),但如果编译器将它们放在每个程序集中,那么如果在不同的程序集中定义了两个具有相同成员的匿名记录,则它们可能是不同的类型。
老实说,我认为您发布的示例在ASP.NET中只是一个糟糕的设计决策 - 它滥用特定的C#功能来做一些它没有设计的东西。它可能没有this那么糟糕,但它仍然很奇怪。该库采用C#匿名类型,但它将其用作字典(即它使用它作为创建键值对的好方法,因为您需要指定的属性是动态的)。
因此,如果您正在使用F#中的ASP.NET,那么在不必创建记录的情况下使用替代方法可能更容易 - 如果ASP.NET API提供了一些替代方法(如Daniel所示,那里是一种更好的写作方式。)
答案 2 :(得分:11)
OP没有描述匿名类型的最佳用法。当使用LINQ映射到任意类时,最好使用它们。例如:
var results = context.Students
.Where(x => x.CourseID = 12)
.Select(x => new {
StudentID = x.ID,
Name = x.Forename + " " + x.Surname
});
我知道这可以通过定义一个新的记录类型来完成,但是你有两个地方来维护代码,(1)你已经使用它的记录类型定义(2)。
它可以用元组完成,但要访问单个字段,您必须始终使用解构语法(studentId, name)
。如果元组中有5个项目,这将变得难以处理。我宁愿输入x
并点击点,并让intellisense告诉我哪些字段可用。
答案 3 :(得分:3)
现在在F#4.6(预览版)中,我们有Anonymous Records
所以我们可以使用以下代码语法:
let AwesomeAnonymous = {| ID = Guid.NewGuid()
Name = "F#"
|}
AwesomeAnonymous.Name |> Debug.WriteLine
Visual Studio Intellisense也支持它:
这样的代码可能像这样:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
{| controller = "Home"; action = "Index"; id = UrlParameter.Optional |} // Parameter defaults
)
答案 4 :(得分:2)
这是我对默认网络项目路线配置的看法:
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])
答案 5 :(得分:0)
正如Tony在他的回答中指出的那样,这与F#4.6相比并没有多少好。使用 .NET Core SDK 3.0.100-preview4-011158 测试类似的示例,我能够演示新Anonymous Record功能的使用。至于RouteMap
方法,我不知道此API接受哪种类型的值,但我怀疑下面的示例是否可以工作。
例如。
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
{| controller = "Home"; action = "Index"; id = UrlParameter.Optional |} // Parameter defaults
)
请注意在花括号内部使用|
字符。这就是现在将常规记录与F#中的匿名记录区分开的地方。
对于您的其他示例,也许现在F#示例如下所示。
let a = {| name = "cow"; sound = "moooo"; omg = "wtfbbq" |}