1

我想从 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);
    }
  }
}
4

3 回答 3

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在代码中使用 as 注释构造函数。我还添加了Id在创建对象时设置属性的构造函数主体。

于 2011-09-21T00:59:56.013 回答
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
于 2011-09-21T00:29:52.750 回答
0

@Tomas 我对您的回复感到荣幸,并为您所做的努力所感动——下载 CSLA,将表达式识别为问题,并创建一种不明显的方式来处理它。我喜欢你的书《真实世界函数式编程》,它超越了语言特性,并探讨了如何将它们应用于重要的现实世界问题。

CSLA 在 C# 有 lambda 之前就已经出现了,所以我回去看看 Lhotka 是如何使用 RegisterProperty 的。如果其他用户想要避免表达,看起来这也有效:

static let IdProperty =
  ReadOnlyBase<ResourceInfo>.RegisterProperty
    (typeof<ResourceInfo>, new PropertyInfo<int>("Id"))
于 2011-09-21T21:48:39.633 回答