我们有一个F#程序集(AssemblyOne
)在单个Visual Studio 2012解决方案中引用另一个F#程序集(AssemblyTwo
)。 AssemblyTwo
引用了C#DLL(MyCSharpLib
)。
AssemblyOne
中定义的函数调用AssemblyTwo
中定义的函数:
namespace AssemblyOne
[<RequireQualifiedAccess>]
module MyModuleA =
let FetchResult id =
let result = AssemblyTwo.MyModuleC.FetchResult id
result
AssemblyTwo
中调用的函数在同一个程序集中调用另一个函数(FetchActualResult()
),该函数接受属于引用的C#DLL MyCSharpType
的类型MyCSharpLib
的参数):
namespace AssemblyTwo
[<RequireQualifiedAccess>]
module MyModuleB =
let FetchActualResult(myCSharpType:MyCSharpLib.MyCSharpType, id:int)
//return a result
[<RequireQualifiedAccess>]
module MyModuleC =
let FetchResult id =
let myCSharpType = new MyCSharpLib.MyCSharpType()
MyModuleB.FetchActualResult(myCSharpType, id)
该解决方案在Visual Studio中编译和构建;但是,当我们尝试使用MSBuild从命令行构建项目时,构建失败,msbuild.log中出现以下错误:
error FS0074: The type referenced through 'MyCSharpLib' is defined in an assembly that is not referenced. You must add a reference to assembly 'MyCSharpLib'.
MyCSharpLib
FetchActualResult()
中的AssemblyTwo
函数签名中显示的AssemblyOne
参数类型会导致错误。
MyCSharpLib
现在需要引用AssemblyOne
,即使MyCSharpLib
没有直接使用AssemblyOne
中的任何内容。
如果我们从函数签名中删除参数,则解决方案构建时没有错误。
我们通过使用以下用例复制代码来进一步探索此问题(' - &gt;'表示程序集引用):
AssemblyTwo
- &gt; F#MyCSharpLib
- &gt; AssemblyOne
(C#DLL)(不构建)AssemblyTwo
- &gt; F#MyFSharpLib
- &gt; AssemblyOne
(F#DLL)(不构建)AssemblyTwo
- &gt; F#AssemblyThree
- &gt; C#AssemblyOne
(在同一解决方案中汇编)(不构建)AssemblyTwo
- &gt; F#AssemblyThree
- &gt; F#public static OkHttpClient getUnsafeOkHttpClient() {
try {
File mFolder = new File(Environment.getExternalStorageDirectory() + "/certificate");
if (!mFolder.exists())
{
mFolder.mkdir();
}
String fileName = "certificate1a.cer";
File file = new File(mFolder, fileName);
FileInputStream fis = null;
fis = new FileInputStream(file);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = cf.generateCertificate(fis);
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("TSL");
sslContext.init(null, tmf.getTrustManagers(),null);
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setSslSocketFactory(sslSocketFactory);
okHttpClient.interceptors().add(new APIRequestInterceptor());
okHttpClient.interceptors().add(new APIResponseInterceptor());
okHttpClient.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslSession) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
Log.e("hey", "inside this");
Log.e("HOST VERIFIER", hv.toString());
Log.e("HOST NAME", hostname);
return hv.verify("aviatesoftware.in", sslSession);
}
});
return okHttpClient;
} catch (Exception e) {
Log.e("error while getting ","unsafeOkHttpClient "+e.toString());
}
return null;
}
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(getUnsafeOkHttpClient())
.build();
return retrofit.create(serviceClass);
}
GetInterface obj = createService(GetTaxInterface.class);
Call<Abc> call = obj.getAbc("555555555555");
call.enqueue(new Callback<Abc>() {
@Override
public void onResponse(Response<Abc> response, Retrofit retrofit) {
Log.e("Asynchronous response", response.toString());
Abc temp = response.body();
Log.e("tax object", temp.toString());
Toast.makeText(getApplicationContext(),"Retrofit Asynchonus Simple try successful",Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Throwable t) {
Log.e("on Failure", t.toString());
Toast.makeText(getApplicationContext(),"Retrofit Asynchonus Simple try failed",Toast.LENGTH_SHORT).show();
}
});
(在同一解决方案中组装)(构建)可以解释这种行为吗?
答案 0 :(得分:1)
假设DWright指出您的源中存在拼写错误,我说这个错误可能源于这样一个事实:通过此代码,您可以使用外部类型的公开方法参数定义静态类MyModuleB MyCsharpType。
这就是Fsharp代码转换为IL的方式(来自ILSpy - 重新转换为Csharp):
...
public static class MyModuleB
{
public static string FetchActualResult(MyCSharpType myCSharpType, int id)
{
return myCSharpType.Fetch(id);
}
}
如果您没有公开该类型以使其静态可见,则可能不会显示错误。但是,这取决于编译器的实现。
我可以想象,在编译MyModuleA期间,编译过程或编译器版本的一个配置可以尝试触摸&#34; MyModuleB,因此尝试到达未引用的参数类型,其他可能只是不触及MyModuleB。这取决于。
所以问题似乎在于我不在编译过程中,但事实上,你暴露了一个你不会引用它的程序集的类型的用法。
答案 1 :(得分:0)
我刚才用这种方式解决了类似的问题。试试这个。
在MyModuleC结束时,添加以下行:
let fetchResult = FetchResult
然后,在MyModuleA中,调用fetchResult而不是FetchResult。当然有论据。
是的,我知道这听起来很傻,但请尝试一下。我相信它会打破不必要的依赖。
如果您按原样使用C#中的AssemblyTwo,您可能不会遇到此问题。当你从F#使用AssemblyTwo时它会浮出水面,所以我想知道F#编译器是否存在问题,或者它可能与curry有关,这超出了我的范围。无论如何,我希望F#编译器更智能。也许某人应该提出问题,除非它已经完成。