简体   繁体   中英

How to help type inference using C# classes in F#

Using bouncy castle v.1.0.1 which is written in C# I'm having issues with type inference. The C# code has a lot of inheritance and interface usage.

// Definitions
public interface IParameters<out TAlg> where TAlg: Algorithm { ... }

public abstract class SignatureParameters<TParam, TAlg, DAlg> : Parameters<TAlg>, ISignatureParameters<TParam, TAlg, DAlg>
    where TParam : IParameters<TAlg>
    where TAlg : Algorithm
    where DAlg : DigestAlgorithm {}

// SignatureFactory interface 
public interface ISignatureFactoryService
{
   ISignatureFactory<A> CreateSignatureFactory<A>(A algorithmDetails) where A : IParameters<Algorithm>;
}

// SignatureFactory creation
public class SomeClass : ISignatureFactoryService
{
   public ISignatureFactory<A> CreateSignatureFactory<A>(A algorithmDetails) where A : IParameters<Algorithm>
   {
       ...
       return (ISignatureFactory<A>)new SignatureFactory<Fips.FipsEC.SignatureParameters>(algorithmDetails as Fips.FipsEC.SignatureParameters, new Fips.FipsEC.SignerProvider(algorithmDetails as Fips.FipsEC.SignatureParameters, privateKey));
   }
}

Now when I use the library from F# the compiler shows issues because it can not resolve/map IParameters<Algorithm> to FipsEC.SignatureParameters

// usage F#
let vKey = ... // is AsymmetricECPrivateKey
let signatureFactoryProvider = CryptoServicesRegistrar.CreateService(vKey, new SecureRandom())
let sigParams = FipsEC.Dsa.WithDigest(FipsShs.Sha256)
// sigParam will be of type FipsEC.SignatureParameters

let sigFactry = signatureFactoryProvider.CreateSignatureFactory(sigParams)
// error, FS0001: The type 'FipsEC.SignatureParameters' is not compatible with the type 'IParameters<Algorithm>'

FipsEC.SignatureParameters is defined as

public class SignatureParameters: SignatureParameters<SignatureParameters, FipsAlgorithm, FipsDigestAlgorithm>
{
    internal SignatureParameters(FipsAlgorithm algorithm, FipsDigestAlgorithm digestAlgorithm): base(algorithm, digestAlgorithm)
    {
    }

    internal override SignatureParameters CreateParameter(FipsAlgorithm algorithm, FipsDigestAlgorithm digestAlgorithm)
    {
        return new SignatureParameters (algorithm, digestAlgorithm);
    }
} 

I tried to define the right type but obviously this is not doing anything


let sigParams =  IParameters<Algorithm> = FipsEC.Dsa.WithDigest(FipsShs.Sha256)   
// error FS0001: this expression was expected to have type 'IParameters<Algorithm>' but here has type 'FipsEC.SignatureParameters' which itself is again Parameters<TAlg>, ISignatureParameters<TParam, TAlg, DAlg> (see above), so it should work...

Question now is, how can I help the compiler? I have tried to cast it, but without luck.

There is no implicit cast in F# (with exception for obj ), so you have to either explicitly cast to interface, or to use flexible types:

1. Explicit cast:

  • using upcast operator:
let sigParams : IParameters<Algorithm> = upcast FipsEC.Dsa.WithDigest(FipsShs.Sha256) 
  • using the safe cast ( :> ) operator:
let sigParams = FipsEC.Dsa.WithDigest(FipsShs.Sha256) :> IParameters<Algorithm>

2. Flexible types (note the # sign before interface type):

let sigParams : #IParameters<Algorithm> = FipsEC.Dsa.WithDigest(FipsShs.Sha256) 

The second one is especially useful in function definitions:

let doSomethingWithParameters<'a> (params: #IParameters<'a>) = // some action here
// ...
// usage of the defined above function:
FipsEC.Dsa.WithDigest(FipsShs.Sha256)
|> doSomethingWithParameters

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM