如何从 F# 中的 CSLA 对象继承?

发布于 2024-12-05 18:28:10 字数 1007 浏览 0 评论 0原文

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

I would like to get the benefits of CSLA from F#, but I am having trouble with inheritance. Here is the ProjectTracker ResourceInfo class. Can someone please show how to do it in 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);
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不弃不离 2024-12-12 18:28:10

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# 表达式树。然后,您可以使用 prop <@ fun (a:Foo) ->; 之类的内容调用 RegisterProperty 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 属性。

The solution by jpalmer shows the general structure, but I think there are a couple of problems. I don't have experience with CSLA, so I haven't tried running this, but I downloaded the DLL and tried type-checking the sample.

First of all, the RegisterProperty method does not take a lambda function, but an expression (and uses it to get information about the property using reflection). To get this working, you need to write a helper using F# quotations:

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"

This turns a quoted F# lambda function to a C# expression tree in the expected format. You can then call RegisterProperty with something like prop <@ fun (a:Foo) -> a.Bar @> as an argument.

I also see that IdProperty should be static, which can be done using static let (if it is private). The following should be the right way of defining type with one property:

[<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)

I generally quite like the style when you write accessibility modifiers directly in your code (as in C#), so I annotated the constructor with internal as in your code. I also added constructor body that sets the Id property when the object is created.

习惯成性 2024-12-12 18:28:10

这应该很接近 - 在 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

This should be close - the standard way to do the access control in F# is to use signature files, which I left out

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
任谁 2024-12-12 18:28:10

@托马斯
我对您的回复感到荣幸,并对您为此付出的努力感到感动——下载 CSLA、将表达式识别为问题,并创建一种非显而易见的方法来处理它。我喜欢你的书,真实世界函数式编程,它超越了语言功能以及如何将它们应用于重要的现实问题。

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

static let IdProperty =
  ReadOnlyBase<ResourceInfo>.RegisterProperty
    (typeof<ResourceInfo>, new PropertyInfo<int>("Id"))

@Tomas
I am honored by your reply and touched by your effort to do so--downloading CSLA, identifying the expression as a problem, and creating a non-obvious way to deal with it. I love your book, Real-World Functional Programming, which goes beyond language features and into how to apply them to important real-world problems.

CSLA was out before C# had lambdas, so I went back to see how Lhotka then used RegisterProperty. If other users want to avoid expressions, it looks like this works, too:

static let IdProperty =
  ReadOnlyBase<ResourceInfo>.RegisterProperty
    (typeof<ResourceInfo>, new PropertyInfo<int>("Id"))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文