公共字段类型的多态性 [英] polymorphism with types for common fields
问题描述
这个问题是否可以通过功能惯用方法解决,泛型或有区别的联合可以成为答案吗?
Is this question solvable through functional idiomatic approach, could generics or discriminated unions be the answer?
当函数使用一些公共字段时,是否可以通过将不同类型传递给函数来实现多态性.
Is it possible to have polymorphism with passing different types to a function while the function is consuming some common fields.
想法是能够调用和重用不同类型的函数并使用公共属性/字段.
Idea is to be able to call and reuse the function with different types and use the common attributes/fields.
type Car = {
Registration: string
Owner: string
Wheels: int
customAttribute1: string
customAttribute2: string
}
type Truck = {
Registration: string
Owner: string
Wheels: int
customField5: string
customField6: string
}
let SomeComplexMethod (v: Car) =
Console.WriteLine("Registration" + v.Registration + "Owner:" + v.Owner + "Wheels" + v.Wheels
// some complex functionality
使用
SomeComplexMethod(car)
SomeComplexMethod(truck)
<小时>
编辑
按照答案.是否可以指定传入 v
的类型,因为 JSON 序列化程序要求关联类型.如果 Car 作为输入提供,Car 将被输出,如果卡车作为输入卡车将被输出.
Following the answer. Is it possible to specify the type of the incoming v
since JSON serializer asks for the associated type. If Car was supplied as input, Car will be output, If truck as input truck will be output.
let inline someComplexFun v =
let owner = (^v: (member Owner: string)(v))
let registration = (^v: (member Registration: string)(v))
// process input
use response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
use memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(reader.ReadToEnd()))
(new DataContractJsonSerializer(typeof<Car>)).ReadObject(memoryStream) :?> Car
如果卡车是输入v
(new DataContractJsonSerializer(typeof<Truck>)).ReadObject(memoryStream) :?> Truck
推荐答案
您想要的通常称为结构(或鸭子)类型.它可以通过 F# 中的接口和对象表达式(公认的方式)或通过 SRTP 来完成.@CaringDev 提供的链接为您提供了一个快速的概要,但显然您可以找到更多示例.请阅读 this 和 这个.对于您的具体示例,这将取决于您对原始类型的控制程度.
What you want is usually called structural (or duck) typing. It can be done via interfaces and object expressions in F# (the accepted way) or via SRTPs. The link @CaringDev provided gives you a quick rundown, but obviously you can find many more examples. Please read this and this. For your specific example it will depend how much control you have over the original types.
定义包含您可能需要的字段的另一种类型很容易.然后你的函数(顺便说一句,我发现它很有趣,你非常想寻求一个功能解决方案但将它命名为一个方法......)应该只采用具有所需字段/属性的任何类型.在这种情况下,泛型对您不起作用,因为您需要限制类型的子集.但是一旦你有了这样一个使用静态解析类型参数 (SRTP) 的函数,你就可以开始了:
It's easy to define another type that includes the fields that you might want. Then your function (I found it interesting btw, that you so much want to go for a functional solution but named it a method...) should just take ANY type that has the required fields/properties. Generics won't work for you in this case, as you need to constrain to a subset of types. But once you have such a function, which uses statically resolved type parameters (SRTPs) you're good to go:
type Car = {
Registration: string
Owner: string
Wheels: int
customAttribute1: string
customAttribute2: string
}
type Truck = {
Registration: string
Owner: string
Wheels: int
customField5: string
customField6: string
}
type Bike = {
Owner: string
Color: string
}
type Vehicle = {
Registration: string
Owner: string
}
let inline someComplexFun v =
let owner = (^v: (member Owner: string)(v))
let registration = (^v: (member Registration: string)(v))
{Registration = registration; Owner = owner}
let car = {Car.Registration = "xyz"; Owner = "xyz"; Wheels = 3; customAttribute1= "xyz"; customAttribute2 = "xyz"}
let truck = {Truck.Registration = "abc"; Owner = "abc"; Wheels = 12; customField5 = "abc"; customField6 = "abc"}
let bike = {Owner = "hell's angels"; Color = "black"}
someComplexFun car //val it : Vehicle = {Registration = "xyz";
//Owner = "xyz";}
someComplexFun truck //val it : Vehicle = {Registration = "abc";
//Owner = "abc";}
someComplexFun bike //error FS0001:
Vehicle
类型已定义,但它可以是任何类型.然后定义了someConplexFun
,它可以采用任何类型,具有Owner
和Registration
.它必须是 inline
并且它的类型签名是:
The Vehicle
type is defined but it could be anything. Then someConplexFun
is defined that can take any type, that has Owner
and Registration
. It has to be inline
and its type signature is:
val 内联 someComplexFun :
v: ^v -> 车辆
当 ^v : (成员 get_Owner : ^v -> 字符串) 和
^v : (成员 get_Registration : ^v -> 字符串)
val inline someComplexFun :
v: ^v -> Vehicle
when ^v : (member get_Owner : ^v -> string) and
^v : (member get_Registration : ^v -> string)
您可以传递任何具有 Owner
和 Registration
字段的类型,它会返回一个 Vehicle
但当然您可以只打印它out 或返回一个元组等.对于 Bike
类型,由于它没有 Registration
,此函数将失败.
You can pass any type that has Owner
and Registration
fields, and it will return a Vehicle
but of course you can just print it out or return a tuple, etc. For the Bike
type, since it doesn't have Registration
this function will fail.
这篇关于公共字段类型的多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!