我已经在VS 2015和F#4.0(4.4.0.0)中开发了很长一段时间.
随着VS 2017的发布,我想在最新的VS开放解决方案中进行开发工作,但仍有一段时间将项目保持为VS 2015,F#4.0,.NET 4.5.2.构建服务器还必须使用VS 2015一段时间.
据我所知,这种情况在早期的VS版本升级中并没有出现问题,但后来我认为我没有使用过F#.
我打开解决方案并尝试编译.我在C#应用程序项目中遇到此错误.(还有其他C#应用程序,至少有一个引用F#库.)
未知的构建错误,'无法解析对程序集的依赖关系'FSharp.Core,Version = 4.4.1.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a',因为它尚未预加载.使用ReflectionOnly API时,必须通过ReflectionOnlyAssemblyResolve事件按需预加载或加载相关的程序集.
解决方案中的所有F#项目都是4.0(4.4.0.0).我仔细检查过.
为什么会这样?
我有一些F#4.0源代码在Debug中编译良好,但在Release中没有.
没有条件定义,推断类型没有变化,也没有其他我能想到的,这可以解释这个差异给我.
我是否真的偶然发现了编译器错误?
这是一个有问题的代码片段.
let oldItems = userDisplayItems |> Seq.toList
for newItem in newItems do
match List.tryFind (fun (itemOfOld: UserDisplay.UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
| Some oldItem ->
Run Code Online (Sandbox Code Playgroud)
错误消息指的是最后一次使用"oldItems",在长行末尾的"with"关键字之前.错误消息是:
未定义的值'oldItems:UserDisplayItem list'
什么!?oldItems在上面几行显而易见,这在Debug中编译,为什么不在Release中呢?该错误消息实际上意味着什么?
UserDisplayItem是一个简单的类.newItems是UserDisplayItem的ResizeArray
我查看了构建历史,当UserDisplayItem是F#immutable记录而不是类时,它在Release中编译得很好.
Visual Studio 2015,F#4.0,任何CPU,Release,.NET 4.5.2都是针对性的.
更新:
以下是一个完整的例子.您可以创建一个F#控制台应用程序,并将其粘贴到Program.fs中.我希望它将在Debug中编译,但不会在Release中编译.
open System.Collections.ObjectModel
type User = { Id: int }
[<AllowNullLiteral>]
type UserDisplayItem(id: int) =
let mutable id = id
member x.Id with get() = id and set(v) = id <- v
let userDisplayItems = new ObservableCollection<UserDisplayItem>()
let refreshList …Run Code Online (Sandbox Code Playgroud) 我试图理解fable-Elmish中mkSimple和mkProgram之间的区别,或者我实际使用的Elmish.WPF.(有人可能会为elmish.wpf生成一个标签吗?)
我发现Elmish.WPF非常有效,我在生产中使用它,但我现在处于一个我每天仍在学习的阶段.这个特殊的问题吞噬了我太多的研究时间,所以我很感激一些帮助.
源代码中的注释如下所示.
mkSimple: Simple program that produces only new state with 'init' and 'update'.
mkProgram: Typical program, new commands are produced by 'init' and 'update' along with the new state.
那些命令有什么用呢?我已经在几个地方看了一些例子,但他们并没有提供很多线索,我是否可以使用mkSimple和mkProgram一样,这就是我需要知道的.
mkProgram是否暴露了mkSimple没有的功能,或者无论我使用哪一个都能完成所有功能?mkSimple仅用于简单的演示使用吗?我应该将mkProgram用于增长的真实世界应用程序吗?如果你能同时做到这两点,那为什么会有区别?
我有一个解决方案,其中主要是F#的.NET Framework项目,然后是C#的几个。我使用Paket而不是NuGet进行数据包管理。现在,我已经向该解决方案添加了我的第一个.NET Standard 2.0库。
当我运行构建脚本时,该脚本运行另一个构建脚本,该脚本调用devenv进行编译,但出现错误,指出该项目的obj \ project.assets.json文件丢失。它实际上是在编译时生成的,但前提是要编译其他项目之一。为什么然后将其报告为缺失有点奇怪。
如果我只运行内部脚本,那没有问题。如果我打开VS并进行编译,那没有问题。滑稽。
我不太确定这些东西是如何工作的-否。但是在谷歌搜索之后,似乎应该在使用devenv(Visual Studio)进行编译之前将该文件放置在此处,而不是使用devenv放置在此处。
我运行了Paket恢复。那并没有产生丢失的project.assets.json。
我用谷歌搜索了“恢复dotnet”。运行此命令时,在一些较旧的项目中出现此错误。
MSB4020: The value "" of the "Project" attribute in element <Import> is invalid.
Run Code Online (Sandbox Code Playgroud)
所以问题是,我现在该怎么办?
我正在研究的项目必须根据明天带来食物的东西从C#迁移到F# - 换句话说,这两种语言必须在未来几年内在这个项目中并存.
我反复面临的问题是如何在解决方案中组织项目以满足这一需求.
我一直将C#中的碎片翻译成F#,因为它经常缩短开发时间并提高质量.但我最终得到了想要使用F#代码的C#代码,以及想要在同一层中或在层或模块之间的边界使用C#代码的F#代码.我发现自己将代码放在错误的项目中只是为了避免在某个层中创建另一个项目.
现在情况还不错,但我担心我会在某个时刻把自己画成一个角落,除非我能想出一个模式或结构,或者只是更好地理解问题.
是否对正常的F#架构(模式,子结构或上层结构)进行了一些修改,非常适合这种混合解决方案?
是否存在已知特别有助于解决此特定挑战的模式?
此代码段再现了我使用某些生产代码时遇到的问题.函数containsProperty表示实际上在库中的真实世界函数,因此我对签名是什么没有发言权.
问题是我无法弄清楚如何创建一个可以将普通函数作为参数的包装函数,然后将其传递给containsProperty.我可以直接使用函数作为lambda表达式调用containsProperty,但我无法使用来自其他来源的函数调用它.
函数addToGroup是迄今为止我提出的最好的函数,它使用了引用.这种方法存在两个问题,我想弄清楚.首先,我如何摆脱报价中的Func演员?也许以某种方式将其移动到addToGroup?第二,我可以在此基础上建立一个函数吗?我没有成功找到一些不会产生编译时错误或运行时错误的东西.
函数addToGroup2是我想做的,但它不能编译.错误消息"没有构造函数可用于类型'Quotations.Expr <'a>'".
为什么我还要为此而烦恼呢?因为只要我不能将传入函数视为第一类值,我就无法创建我所追求的设计.我希望这些函数来自一组记录.
如果将此代码段粘贴到LINQPad或其他内容中,请注释掉addToGroup2及其调用,以便使代码段编译并运行.
open System
open System.ComponentModel
open System.ComponentModel.DataAnnotations // Reference to this assembly required.
type CfgSettings = {
mutable ConnectionString: string
mutable Port: int
}
and CfgSettingsMetadata() =
static member containsProperty<'TProperty>(propertyExpression: Linq.Expressions.Expression<Func<CfgSettings,'TProperty>>) =
Console.WriteLine "good!"
static member addToGroup f =
CfgSettingsMetadata.containsProperty(FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression f) |> ignore
static member addToGroup2 (f: CfgSettings -> 'TProperty) =
CfgSettingsMetadata.containsProperty(FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression (Quotations.Expr<Func<CfgSettings,'TProperty>>f)) |> ignore
static member BuildMetadata () =
CfgSettingsMetadata.containsProperty(fun x -> x.ConnectionString)
CfgSettingsMetadata.containsProperty(fun x -> x.Port)
CfgSettingsMetadata.addToGroup <@ Func<_,_>(fun x -> x.ConnectionString) …Run Code Online (Sandbox Code Playgroud) 我想将下面的C#方法DelayNe转换为F#函数,以便以完全相同的方式从C#中使用它.原因是我想把它放在一个F#库中.我正在苦苦挣扎,试图谷歌我的答案,显然没有运气.
更新:抱歉不清楚.我的任务以您在下面的DelayNe方法中看到的方式调用Task.Delay.问题是,当调用_cancellationTokenSource.Cancel()时,Task.Delay会抛出异常,我不想要那个异常.换句话说,我相信我需要一个围绕Task.Delay的包装器,它将捕获异常并使其静音,但是否则会完全暴露Task.Delay的行为.我想在F#中实现包装器.
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
async Task DelayNe(int milliSeconds, CancellationToken token)
{
try
{
await Task.Delay(milliSeconds, token);
}
catch (TaskCanceledException ex)
{
("Silencing " + ex.GetType().Name + ", " + ex.Message).Dump();
}
}
async Task Test(CancellationToken cancellationToken)
{
try
{
"Test start".Dump();
await DelayNe(5000, cancellationToken);
"Test stop".Dump();
}
catch (Exception ex)
{
("Catch: " + ex.Message + ", " + ex.GetType().Name).Dump();
}
}
async Task Main()
{
"Start".Dump();
_cancellationTokenSource.CancelAfter(1000);
var testTask = Test(_cancellationTokenSource.Token);
await testTask;
"Stop".Dump();
}
Run Code Online (Sandbox Code Playgroud)