我想从F#中获得CSLA的好处,但我在继承方面遇到了麻烦。这是ProjectTracker ResourceInfo类。有人可以在F#中展示如何做到这一点吗?
using Csla;
using System;
using Csla.Serialization;
namespace ProjectTracker.Library
{
[Serializable()]
public class ResourceInfo : ReadOnlyBase<ResourceInfo>
{
private static PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id);
public int Id
{
get { return GetProperty(IdProperty); }
private set { LoadProperty(IdProperty, value); }
}
private static PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
public string Name
{
get { return GetProperty(NameProperty); }
private set { LoadProperty(NameProperty, value); }
}
public override string ToString()
{
return Name;
}
internal ResourceInfo(int id, string lastname, string firstname)
{
Id = id;
Name = string.Format("{0}, {1}", lastname, firstname);
}
}
}
答案 0 :(得分:2)
jpalmer的解决方案显示了一般结构,但我认为存在一些问题。我没有CSLA的经验,所以我没有尝试过运行它,但我下载了DLL并尝试对样本进行类型检查。
首先,RegisterProperty
方法不接受lambda函数,而是接受表达式(并使用它来使用反射获取有关属性的信息)。要使其正常工作,您需要使用F#引用编写帮助程序:
open Microsoft.FSharp.Quotations
open System.Linq.Expressions
let prop (q:Expr<'T -> 'R>) =
match q with
| Patterns.Lambda(v, Patterns.PropertyGet(_, pi, _)) ->
let v = Expression.Variable(v.Type)
Expression.Lambda<Func<'T, 'R>>
(Expression.Property(v, pi), [v])
| _ -> failwith "wrong quotation"
这会将引用的F#lambda函数转换为预期格式的C#表达式树。然后,您可以使用RegisterProperty
之类的内容作为参数调用prop <@ fun (a:Foo) -> a.Bar @>
。
我还看到IdProperty
应该是静态的,可以使用static let
(如果它是私有的)来完成。以下应该是使用一个属性定义类型的正确方法:
[<Serializable>]
type ResourceInfo internal (id:int, lastname:string, firstname:string) as this =
inherit ReadOnlyBase<ResourceInfo>()
// Code executed as part of the constructor
do this.Id <- id
static let IdProperty =
ReadOnlyBase<ResourceInfo>.RegisterProperty<int>
(prop <@ fun (r:ResourceInfo) -> r.Id @>)
member x.Id
with get() = x.GetProperty(IdProperty) |> unbox
and set(v) = x.LoadProperty(IdProperty, v)
我通常非常喜欢在代码中直接编写辅助功能修饰符的样式(如在C#中),因此我在代码中使用internal
注释构造函数。我还添加了构造函数体,它在创建对象时设置Id
属性。
答案 1 :(得分:0)
这应该是关闭的 - 在F#中进行访问控制的标准方法是使用我遗漏的签名文件
module ProjectTracker.Library
open Csla;
open System;
open Csla.Serialization;
[<Serializable>]
type ResourceInfo(id, lastname, firstname) =
inherit ReadOnlyBase<ResourceInfo>()
Id <- id
Name <- sprintf "%s, %s" lastname firstname
let IdProperty = RegisterProperty<int>(fun c -> c.Id);
member x.Id with get() = GetProperty(IdProperty) and set(v) = LoadProperty(IdProperty, v)
//skipped a property here - similar to above
override x.ToString() = Name
答案 2 :(得分:0)
@Tomas 我很荣幸您的回复,并为您的努力所感动 - 下载CSLA,将表达确定为问题,并创建一种非显而易见的方法来处理它。我喜欢你的书Real-World Functional Programming,它超越了语言特征,并且如何将它们应用于重要的现实问题。
在C#有lambda之前CSLA已经出局了,所以我回去看看Lhotka如何使用RegisterProperty。如果其他用户想要避免表达式,它看起来也是如此:
static let IdProperty =
ReadOnlyBase<ResourceInfo>.RegisterProperty
(typeof<ResourceInfo>, new PropertyInfo<int>("Id"))