This answer to this question was provided by Kevin on the MEF discussion list. It turns out that one can extract all the required information from the MEF ExportDefinition and ImportDefinition data structures with the following code snippets.
The first step is to load the assembly types into a catalog. Then for each part in the catalog iterate over the import and export definitions. Export definitions can only be placed on types, methods, properties and fields (which my code ignores at the moment). So to process the exports the following code can be used.
var exports = new List<Tuple<string, MemberInfo>>();
foreach (var export in part.ExportDefinitions)
{
var memberInfo = ReflectionModelServices.GetExportingMember(export);
Tuple<string, MemberInfo> exportDefinition = null;
switch (memberInfo.MemberType)
{
case MemberTypes.Method:
exportDefinition = new Tuple<string, MemberInfo>(export.ContractName, memberInfo.GetAccessors().First() as MethodInfo);
break;
case MemberTypes.NestedType:
case MemberTypes.TypeInfo:
exportDefinition = new Tuple<string, MemberInfo>(export.ContractName, memberInfo.GetAccessors().First() as Type);
break;
case MemberTypes.Property:
// this is a bit ugly because we assume that the underlying methods for a property are named as:
// get_PROPERTYNAME and set_PROPERTYNAME. In this case we assume that exports always
// have a get method.
var getMember = memberInfo.GetAccessors().Where(m => m.Name.Contains("get_")).First();
var name = getMember.Name.Substring("get_".Length);
var property = getMember.DeclaringType.GetProperty(name);
exportDefinition = new Tuple<string, MemberInfo>(export.ContractName, property);
break;
default:
throw new NotImplementedException();
}
exports.Add(exportDefinition);
}
In order to process the imports, which can only be placed on properties, parameters and fields (which are again ignored) the following code can be used:
public void ExtractImports()
{
var imports = new List<Tuple<string, string>>();
foreach (var import in part.ImportDefinitions)
{
SerializedImportDefinition importDefinition = !ReflectionModelServices.IsImportingParameter(import)
? importDefinition = CreatePropertyImport(import)
: importDefinition = CreateConstructorParameterImport(import);
}
}
private Tuple<string, string> CreatePropertyImport(ImportDefinition import)
{
var memberInfo = ReflectionModelServices.GetImportingMember(import);
if (memberInfo.MemberType != MemberTypes.Property)
{
throw new ArgumentOutOfRangeException("import");
}
// this is a bit ugly because we assume that the underlying methods for a property are named as:
// get_PROPERTYNAME and set_PROPERTYNAME. In this case we assume that imports always
// have a set method.
var getMember = memberInfo.GetAccessors().Where(m => m.Name.Contains("set_")).First();
var name = getMember.Name.Substring("set_".Length);
var property = getMember.DeclaringType.GetProperty(name);
return new Tuple<string, string>(import.ContractName, property.ToString());
}
private Tuple<string, string> CreateConstructorParameterImport(ImportDefinition import)
{
var parameterInfo = ReflectionModelServices.GetImportingParameter(import);
return new Tuple<string, string>(import.ContractName, parameterInfo.Value.ToString());
}
Note that it seems that imports cannot be provided via method parameters so the code above does not support those.
Once all the exports and imports have been processed it is a simple question of serializing the stored MemberInfo objects into a string format.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…