公共字段类型的多态性 [英] polymorphism with types for common fields

查看:20
本文介绍了公共字段类型的多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是否可以通过功能惯用方法解决,泛型有区别的联合可以成为答案吗?

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,它可以采用任何类型,具有OwnerRegistration.它必须是 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)

您可以传递任何具有 OwnerRegistration 字段的类型,它会返回一个 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆