Как наследовать от объекта CSLA в F #? - PullRequest
1 голос
/ 21 сентября 2011

Я хотел бы получить преимущества CSLA от F #, но у меня проблемы с наследованием. Вот класс 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);
    }
  }
}

Ответы [ 3 ]

2 голосов
/ 21 сентября 2011

Решение от jpalmer показывает общую структуру, но я думаю, что есть пара проблем.У меня нет опыта работы с CSLA, поэтому я не пытался запустить его, но я скачал DLL и попытался проверить тип образца.

Прежде всего, метод RegisterProperty не требуетлямбда-функция, но выражение (и использует ее для получения информации о свойстве с помощью отражения).Чтобы это работало, вам нужно написать помощник, используя цитаты 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 # в кавычках в дерево выражений 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 при создании объекта.

0 голосов
/ 22 сентября 2011

@ Томас Я удостоен вашего ответа и тронут вашими попытками сделать это - загрузкой CSLA, определением выражения как проблемы и созданием неочевидного способа борьбы с ним. Мне нравится ваша книга, Функциональное программирование в реальном мире , которая выходит за рамки языковых возможностей и того, как применять их к важным реальным проблемам.

CSLA отсутствовал до того, как в C # были лямбды, поэтому я вернулся к тому, как Lhotka тогда использовал RegisterProperty. Если другие пользователи хотят избежать выражений, похоже, это тоже работает:

static let IdProperty =
  ReadOnlyBase<ResourceInfo>.RegisterProperty
    (typeof<ResourceInfo>, new PropertyInfo<int>("Id"))
0 голосов
/ 21 сентября 2011

Это должно быть близко - стандартный способ сделать контроль доступа в 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
...