我正在尝试在F#中创建一小段代码。我的想法是,我将有一个定义一些方法,属性和事件的接口。使用这个接口我想定义一个抽象类(具有泛型类型),它将实现一些属性/方法,但不是所有在接口中定义的成员。定义所有成员的责任在于派生类。
到目前为止,我仍然坚持使用接口和抽象类。我遇到的问题:
接口编译正常,但抽象类有几个错误。消息包含在代码
中所有评论,更正,提示等都表示赞赏。由于这是我对F#的第一次试验,因此可能会指出很多错误。
到目前为止我的代码
接口定义
namespace A
type IValueItem =
interface
[<CLIEvent>]
abstract member PropertyChanged :
Control.IEvent<System.ComponentModel.PropertyChangedEventHandler,
System.ComponentModel.PropertyChangedEventArgs>
abstract ConvertedX : double with get, set
abstract Y : double with get, set
abstract member CreateCopy : obj
abstract member NewTrendItem : obj
end
抽象类
namespace A
[<AbstractClass>]
type ValueItem<'TX>() =
[<DefaultValue>]
val mutable _y : double
let _propertyChanged = new Event<_>()
// ERROR: This type is not an interface type
// ERROR: The type 'obj' is not an interface type
// ERROR: The type 'IValueItem' is not defined
interface IValueItem with
// ERRROR No abstract or interface member was found that corresponds to this override
[<CLIEvent>]
member this.PropertyChanged :
Control.IEvent<System.ComponentModel.PropertyChangedEventHandler,
System.ComponentModel.PropertyChangedEventArgs>
= _propertyChanged.Publish
// This definition is incomplete, should be abstract
member ConvertedX : double with get, set
// ERROR: Incomplete structured construct at or before this point in pattern
member CreateCopy() : obj
member NewTrendItem() : obj
abstract X : 'TX with get, set
member this.Y
with get() = this._y
and set(value) =
if this._y <> value then
this._y <- value
this.NotifyPropertyChanged("Y")
member this.NotifyPropertyChanged(propertyName) =
this.PropertyChanged.Trigger(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName))
答案 0 :(得分:8)
抽象类定义无法识别接口定义
接口必须是declared above抽象类,可以是:在引用的项目/程序集中,在当前文件上方的文件中(文件顺序很重要),或者在同一文件中的上面。
我不确定如何在抽象类
中定义接口的抽象成员
不幸的是我们必须实现接口的所有成员,以保持你想要的行为,你可以让实现调用具有相同签名的类的抽象成员:
public class Class1
{
public IList<Car> getCarsByProjectionOnSmallNumberOfProperties()
{
try
{
//Get the SQL Context:
CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext dbContext
= new CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext();
//Specify the Context of your main entity e.g. Car:
var oDBQuery = dbContext.Set<Car>();
//Project on some of its fields, so the created select statment that is
// sent to the database server, will have only the required fields By making a new anonymouse type
var queryProjectedOnSmallSetOfProperties
= from x in oDBQuery
select new
{
x.carNo,
x.eName,
x.aName
};
//Convert the anonymouse type back to the main entity e.g. Car
var queryConvertAnonymousToOriginal
= from x in queryProjectedOnSmallSetOfProperties
select new Car
{
carNo = x.carNo,
eName = x.eName,
aName = x.aName
};
//return the IList<Car> that is wanted
var lst = queryConvertAnonymousToOriginal.ToList();
return lst;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
throw;
}
}
}
type IValueItem =
[<CLIEvent>]
abstract PropertyChanged :
Control.IEvent<System.ComponentModel.PropertyChangedEventHandler,
System.ComponentModel.PropertyChangedEventArgs>
abstract ConvertedX : double with get, set
abstract Y : double with get, set
abstract CreateCopy : obj
abstract NewTrendItem : obj
[<AbstractClass>]
type ValueItem<'TX>() =
let mutable y = 0.0
let propertyChanged = Event<_, _>()
interface IValueItem with
[<CLIEvent>]
member __.PropertyChanged : Control.IEvent<_, _> = propertyChanged.Publish
member this.ConvertedX
with get() = this.ConvertedX
and set(x) = this.ConvertedX <- x
member this.CreateCopy = this.CreateCopy
member this.NewTrendItem = this.NewTrendItem
member this.Y
with get() = this.Y
and set(y) = this.Y <- y
abstract ConvertedX : double with get, set
abstract CreateCopy : obj
abstract NewTrendItem : obj
member this.Y
with get() = y
and set(value) =
if y <> value then
y <- value
this.NotifyPropertyChanged("Y")
abstract X : 'TX with get, set
member this.NotifyPropertyChanged(propertyName) =
propertyChanged.Trigger(this, System.ComponentModel.PropertyChangedEventArgs(propertyName))
属性定义了两次,起初看起来有点奇怪。接口实现遵循类的实现 - 这意味着要访问Y
,您不需要将类的实例向上转换为接口,我这样做是为了保持与初始化相同的行为示例
发表评论:
要在抽象类上获取虚拟成员,您需要将该成员声明为抽象并提供默认实现,这是一个匹配注释中代码的示例:
Y
通常OO F#用于与.NET世界的其他部分进行交互 - 这看起来就像这里的情况。但是,如果代码没有与需要OO接口的另一个.NET API进行交互,您可能会发现使用功能方法对问题进行建模可能会产生一些更清晰的代码。 F#中的OO可能不会给出语言的初步良好印象(虽然我个人非常喜欢它的明确性和简洁性)