Declaring Imports

 

Declaring Imports 导入声明

Composable Parts declare imports [System.ComponentModel.Composition.ImportAttribute] attribute. Similar to exports, there are several different methods namely through Fields, Properties and Constructor Parameters.

Property Imports 属性导入的声明

To import a value to a property, decorate the property with the [System.ComponentModel.Composition.ImportAttribute]. For example the snippet below imports an IMessageSender
导入一个Value给属性

  class Program
  {
    [Import]
    public IMessageSender MessageSender { get; set; }
  }
Class Program
    <Import()>
    Public Property MessageSender() As IMessageSender
End Class

 

Constructor Parameters 

You can also specify imports through constructor parameters. This means that instead of adding properties for each import, you add parameters to a constructor for each import. To use this, follow the following steps.

1. Add a [System.ComponentModel.Composition.ImportingConstructorAttribute] attribute to the constructor that should be used by MEF. 
2. Add parameters to the constructor for each import.

For example the code below imports a message sender in the constructor of the Program class.

  class Program
  {
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
       ...
    }
  }
Class Program
    <ImportingConstructor()>
    Public Sub New(ByVal messageSender As IMessageSender) 
      ... 
    End Sub
End Class


Parameter imports

There are several different different ways to define imports on the constructor.

1. Implied import - By default the container will use the type of the parameter to identify the contract. For example in the code below, the IMessageSender contract will be used.

  class Program
  {
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    }
  }
Class Program
    <ImportingConstructor()>
    Public Sub New(ByVal messageSender As IMessageSender) 
    End Sub
End Class


2. Explicit import - If you want to specify the contract to be imported add an [System.ComponentModel.Composition.ImportAttribute]attribute to the parameter. 

Field Imports

MEF also supports importing values directly to fields.

  class Program
  {
    [Import]
    private IMessageSender _messageSender;
  }
Class Program
    <Import()>
    Private _messageSender As IMessageSender
End Class


Note: note that importing or exporting private members (fields, properties and methods) while supported in full trust is likely to be problematic on medium/partial trust.

Optional imports

MEF allows you to specify that an import is optional. When you enable this, the container will provide an export if one is available otherwise it will set the import to Default(T). To make an import optional, set AllowDefault=true on the import as below.

[Export]
public class OrderController {
  private ILogger _logger;

  [ImportingConstructor]
  public OrderController([Import(AllowDefault=true)] ILogger logger) {
    if(logger == null)
      logger = new DefaultLogger();
    _logger = logger;
  }
}
<Export()>
Public Class OrderController
    Private _logger As ILogger

    <ImportingConstructor()>
    Public Sub New(<Import(AllowDefault:=True)> ByVal logger As ILogger) 
        If logger Is Nothing Then
            logger = New DefaultLogger()
        End If
        _logger = logger
    End Sub
End Class


OrderController optionally imports a logger. If the logger is not present, it will set it's private _logger to a new DefaultLogger instance otherwise it will use the imported logger.

Importing collections

In addition to single imports, you can import collections with the ImportMany attribute. This means that all instances of the specific contract will be imported from the container.

MEF parts can also support recomposition. This means that as new exports become available in the container, collections are automatically updated with the new set. For example below the Notifier class imports a collection of IMessageSender. This means if there are 3 exports of IMessageSender available in the container, they will be pushed in to the Senders property during compositon.

 public class Notifier 
 {
    [ImportMany(AllowRecomposition=true)]
    public IEnumerable<IMessageSender> Senders {get; set;}

    public void Notify(string message) 
    {
      foreach(IMessageSender sender in Senders)
      {
        sender.Send(message);
      }
    } 
  }
Public Class Notifier
    <ImportMany(AllowRecomposition:=True)> 
    Public Property Senders() As IEnumerable(Of IMessageSender) 

    Public Sub Notify(ByVal message As String) 
        For Each sender As IMessageSender In Senders
            sender.Send(message) 
        Next sender
    End Sub
End Class

IPartImportsSatisfiedNotification

In some situations it may be important for your class to be notified when MEF is done with the import process for your class instance. If that's the case implement the [System.ComponentModel.Composition.IPartImportsSatisfiedNotification] interface. This interface has only a single method: OnImportsSatisfied, which is called when all imports that could be satisfied have been satisfied.

 public class Program : IPartImportsSatisfiedNotification
 {
    [ImportMany]
    public IEnumerable<IMessageSender> Senders {get; set;}

    public void OnImportsSatisfied() 
    {
      // when this is called, all imports that could be satisfied have been satisfied.
    } 
  }
Public Class Program
    Implements IPartImportsSatisfiedNotification
    <ImportMany()>
    Public Property Senders() As IEnumerable(Of IMessageSender) 

    Public Sub OnImportsSatisfied() Implements IPartImportsSatisfiedNotification.OnImportsSatisfied
        ' when this is called, all imports that could be satisfied have been satisfied. 
    End Sub
End Class

 

<think>嗯,用户想知道如何在C/C++中正确声明库函数,避免隐式声明导致的警告或错误。首先,我需要回忆一下隐式声明的问题。在C语言中,如果调用一个函数之前没有声明它的原型,编译器会假设这个函数返回int类型,并且参数类型根据实际调用参数推导。如果实际函数的返回类型不是int,或者参数不匹配,就会导致问题,比如运行时错误或者不可预测的行为。C++在这方面更严格,直接不允许隐式声明,所以问题可能更多出现在C代码中。 那用户遇到的应该是类似“implicit declaration of function”这样的警告或者错误。要解决这个问题,首先应该确保在调用函数之前有正确的函数声明。这通常包括包含正确的头文件,比如标准库函数如printf需要包含stdio.h,数学函数如sqrt需要math.h,等等。如果用户使用的是第三方库,可能需要包含对应的头文件,并确保链接时正确指定库路径。 接下来,可能需要检查头文件是否正确包含。有时候拼写错误或者路径问题会导致头文件没有被正确包含,从而函数没有被声明。另外,在C99标准之后,隐式函数声明已经被禁止,所以如果用户使用的编译器支持C99或更高版本,隐式声明会导致错误而非警告。这时候必须显式声明函数。 对于用户自己编写的函数,如果在调用之前没有声明或定义,也会出现这个问题。这时候需要在调用之前提供函数原型,或者在文件开头声明函数。比如,如果有一个函数void myFunction(int a),在调用前需要声明void myFunction(int a);。 另外,需要注意函数签名的一致性。如果声明和定义的返回类型或参数不一致,会导致链接错误或者运行时错误。所以,在头文件中声明函数时,必须和实际定义的函数完全一致。 还可能涉及到编译器选项的问题。比如,使用gcc编译时,如果忘记链接数学库,需要使用-lm选项。否则,虽然声明了数学函数,但链接时会找不到定义,导致错误。 此外,在C++中,函数重载和类型安全更为严格,所以必须确保函数声明正确,否则会直接报错。而C中的问题更多是警告,但如果不处理,可能导致未定义行为。 最后,可能需要检查是否使用了过时的库或者不推荐的做法。例如,某些旧的库可能没有提供标准的头文件,需要手动声明函数,但这样做有风险,应该尽量使用最新的库版本,并遵循文档中的指导。 总结来说,解决隐式声明问题的步骤包括:包含正确的头文件、检查拼写和路径、声明用户自定义函数、确保编译器标准符合预期、正确链接库,以及验证函数签名的一致性。此外,参考编译器的文档和错误信息,能更有效地定位问题所在。</think>在C/C++中正确声明库函数以避免隐式声明警告/错误,需要遵循以下关键步骤: ### 1. 包含标准头文件 所有标准库函数都应在调用前包含对应的头文件: ```c #include <stdio.h> // 例如 printf/scanf #include <stdlib.h> // 例如 malloc/free #include <math.h> // 例如 sqrt/pow ``` 例如使用`sqrt()`时缺少`math.h`会导致: $$ \text{implicit declaration warning} \Rightarrow \text{潜在的类型不匹配风险} $$ ### 2. 第三方库的特殊处理 对第三方库(如OpenSSL)需同时包含头文件和链接库: ```c #include <openssl/ssl.h> // 声明函数 ``` 编译时添加链接参数: ```bash gcc -o program program.c -lssl -lcrypto # OpenSSL链接示例 ``` ### 3. 自定义函数的显式声明 在调用自定义函数前必须声明原型: ```c // 头文件 mylib.h void custom_function(int param); // 显式声明 // 源文件中 #include "mylib.h" // 确保声明可见性 ``` ### 4. 编译器标准设置(C语言) 对于C代码,建议启用严格模式: ```bash gcc -std=c11 -pedantic-errors -Werror # 强制C11标准并将警告转为错误 ``` 这会禁止隐式函数声明[^1] ### 5. 参数类型验证 特别注意可变参数函数: ```c // 错误示范(缺少<stdarg.h>) void log_message(const char* fmt, ...); // 需要完整声明 ``` ### 6. C++的严格类型检查 C++要求更严格的类型匹配: ```cpp extern "C" { // 用于C库函数 #include <libavcodec/avcodec.h> // FFmpeg示例 } ``` **常见错误案例**: ```c // 错误:未包含<stdio.h> int main() { printf("Hello"); // 触发隐式声明警告 return 0; } ``` 修正方案: $$ \text{添加} \quad \#include <stdio.h> $$ **附加建议**: - 使用静态分析工具(如Clang-Tidy) - 启用编译器所有警告选项(-Wall -Wextra) - 定期检查废弃函数声明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值