File-scoped namespaces in files under `ComponentModel` (`Microsoft.ML.Core`) (#6788)
Co-authored-by: Lehonti Ramos <john@doe>
This commit is contained in:
Родитель
e3f53a4497
Коммит
34389b63e5
|
@ -8,286 +8,285 @@ using System.IO.Compression;
|
|||
using System.Reflection;
|
||||
using Microsoft.ML.Internal.Utilities;
|
||||
|
||||
namespace Microsoft.ML.Runtime
|
||||
namespace Microsoft.ML.Runtime;
|
||||
|
||||
[Obsolete("The usage for this is intended for the internal command line utilities and is not intended for anything related to the API. " +
|
||||
"Please consider another way of doing whatever it is you're attempting to accomplish.")]
|
||||
[BestFriend]
|
||||
internal static class AssemblyLoadingUtils
|
||||
{
|
||||
[Obsolete("The usage for this is intended for the internal command line utilities and is not intended for anything related to the API. " +
|
||||
"Please consider another way of doing whatever it is you're attempting to accomplish.")]
|
||||
[BestFriend]
|
||||
internal static class AssemblyLoadingUtils
|
||||
/// <summary>
|
||||
/// Make sure the given assemblies are loaded and that their loadable classes have been catalogued.
|
||||
/// </summary>
|
||||
public static void LoadAndRegister(IHostEnvironment env, string[] assemblies)
|
||||
{
|
||||
/// <summary>
|
||||
/// Make sure the given assemblies are loaded and that their loadable classes have been catalogued.
|
||||
/// </summary>
|
||||
public static void LoadAndRegister(IHostEnvironment env, string[] assemblies)
|
||||
Contracts.AssertValue(env);
|
||||
|
||||
if (Utils.Size(assemblies) > 0)
|
||||
{
|
||||
Contracts.AssertValue(env);
|
||||
|
||||
if (Utils.Size(assemblies) > 0)
|
||||
foreach (string path in assemblies)
|
||||
{
|
||||
foreach (string path in assemblies)
|
||||
Exception ex = null;
|
||||
try
|
||||
{
|
||||
Exception ex = null;
|
||||
try
|
||||
// REVIEW: Will LoadFrom ever return null?
|
||||
Contracts.CheckNonEmpty(path, nameof(path));
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
// REVIEW: Will LoadFrom ever return null?
|
||||
Contracts.CheckNonEmpty(path, nameof(path));
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw Contracts.ExceptParam(nameof(path), "File does not exist at path: {0}", path);
|
||||
}
|
||||
var assem = LoadAssembly(env, path);
|
||||
if (assem != null)
|
||||
continue;
|
||||
throw Contracts.ExceptParam(nameof(path), "File does not exist at path: {0}", path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ex = e;
|
||||
}
|
||||
|
||||
// If it is a zip file, load it that way.
|
||||
ZipArchive zip;
|
||||
try
|
||||
{
|
||||
zip = ZipFile.OpenRead(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Couldn't load as an assembly and not a zip, so warn the user.
|
||||
ex = ex ?? e;
|
||||
Console.Error.WriteLine("Warning: Could not load '{0}': {1}", path, ex.Message);
|
||||
var assem = LoadAssembly(env, path);
|
||||
if (assem != null)
|
||||
continue;
|
||||
}
|
||||
|
||||
string dir;
|
||||
try
|
||||
{
|
||||
dir = CreateTempDirectory();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Contracts.ExceptIO(e, "Creating temp directory for extra assembly zip extraction failed: '{0}'", path);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
zip.ExtractToDirectory(dir);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Contracts.ExceptIO(e, "Extracting extra assembly zip failed: '{0}'", path);
|
||||
}
|
||||
|
||||
LoadAssembliesInDir(env, dir, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IDisposable CreateAssemblyRegistrar(IHostEnvironment env, string loadAssembliesPath = null)
|
||||
{
|
||||
Contracts.CheckValue(env, nameof(env));
|
||||
env.CheckValueOrNull(loadAssembliesPath);
|
||||
|
||||
return new AssemblyRegistrar(env, loadAssembliesPath);
|
||||
}
|
||||
|
||||
public static void RegisterCurrentLoadedAssemblies(IHostEnvironment env)
|
||||
{
|
||||
Contracts.CheckValue(env, nameof(env));
|
||||
|
||||
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
TryRegisterAssembly(env.ComponentCatalog, a);
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateTempDirectory()
|
||||
{
|
||||
string dir = GetTempPath();
|
||||
Directory.CreateDirectory(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
private static string GetTempPath()
|
||||
{
|
||||
Guid guid = Guid.NewGuid();
|
||||
return Path.GetFullPath(Path.Combine(Path.GetTempPath(), "MLNET_" + guid.ToString()));
|
||||
}
|
||||
|
||||
private static readonly string[] _filePrefixesToAvoid = new string[] {
|
||||
"api-ms-win",
|
||||
"clr",
|
||||
"coreclr",
|
||||
"dbgshim",
|
||||
"ext-ms-win",
|
||||
"microsoft.bond.",
|
||||
"microsoft.cosmos.",
|
||||
"microsoft.csharp",
|
||||
"microsoft.data.",
|
||||
"microsoft.hpc.",
|
||||
"microsoft.live.",
|
||||
"microsoft.platformbuilder.",
|
||||
"microsoft.visualbasic",
|
||||
"microsoft.visualstudio.",
|
||||
"microsoft.win32",
|
||||
"microsoft.windowsapicodepack.",
|
||||
"microsoft.windowsazure.",
|
||||
"mscor",
|
||||
"msvc",
|
||||
"petzold.",
|
||||
"roslyn.",
|
||||
"sho",
|
||||
"sni",
|
||||
"sqm",
|
||||
"system.",
|
||||
"zlib",
|
||||
};
|
||||
|
||||
private static bool ShouldSkipPath(string path)
|
||||
{
|
||||
string name = Path.GetFileName(path).ToLowerInvariant();
|
||||
switch (name)
|
||||
{
|
||||
case "cpumathnative.dll":
|
||||
case "cqo.dll":
|
||||
case "fasttreenative.dll":
|
||||
case "libiomp5md.dll":
|
||||
case "ldanative.dll":
|
||||
case "libvw.dll":
|
||||
case "matrixinterf.dll":
|
||||
case "microsoft.ml.neuralnetworks.gpucuda.dll":
|
||||
case "mklimports.dll":
|
||||
case "microsoft.research.controls.decisiontrees.dll":
|
||||
case "microsoft.ml.neuralnetworks.sse.dll":
|
||||
case "mklproxynative.dll":
|
||||
case "neuraltreeevaluator.dll":
|
||||
case "optimizationbuilderdotnet.dll":
|
||||
case "parallelcommunicator.dll":
|
||||
case "Microsoft.ML.runtests.dll":
|
||||
case "scopecompiler.dll":
|
||||
case "symsgdnative.dll":
|
||||
case "tbb.dll":
|
||||
case "internallearnscope.dll":
|
||||
case "unmanagedlib.dll":
|
||||
case "vcclient.dll":
|
||||
case "libxgboost.dll":
|
||||
case "zedgraph.dll":
|
||||
case "__scopecodegen__.dll":
|
||||
case "cosmosClientApi.dll":
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var s in _filePrefixesToAvoid)
|
||||
{
|
||||
if (name.StartsWith(s, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void LoadAssembliesInDir(IHostEnvironment env, string dir, bool filter)
|
||||
{
|
||||
if (!Directory.Exists(dir))
|
||||
return;
|
||||
|
||||
// Load all dlls in the given directory.
|
||||
var paths = Directory.EnumerateFiles(dir, "*.dll");
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (filter && ShouldSkipPath(path))
|
||||
catch (Exception e)
|
||||
{
|
||||
ex = e;
|
||||
}
|
||||
|
||||
// If it is a zip file, load it that way.
|
||||
ZipArchive zip;
|
||||
try
|
||||
{
|
||||
zip = ZipFile.OpenRead(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Couldn't load as an assembly and not a zip, so warn the user.
|
||||
ex = ex ?? e;
|
||||
Console.Error.WriteLine("Warning: Could not load '{0}': {1}", path, ex.Message);
|
||||
continue;
|
||||
}
|
||||
|
||||
LoadAssembly(env, path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given an assembly path, load the assembly and register it with the ComponentCatalog.
|
||||
/// </summary>
|
||||
private static Assembly LoadAssembly(IHostEnvironment env, string path)
|
||||
{
|
||||
Assembly assembly = null;
|
||||
try
|
||||
{
|
||||
assembly = Assembly.LoadFrom(path);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (assembly != null)
|
||||
{
|
||||
TryRegisterAssembly(env.ComponentCatalog, assembly);
|
||||
}
|
||||
|
||||
return assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether <paramref name="assembly"/> references the assembly containing LoadableClassAttributeBase,
|
||||
/// and therefore can contain components.
|
||||
/// </summary>
|
||||
private static bool CanContainComponents(Assembly assembly)
|
||||
{
|
||||
var targetFullName = typeof(LoadableClassAttributeBase).Assembly.GetName().FullName;
|
||||
|
||||
bool found = false;
|
||||
foreach (var name in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
if (name.FullName == targetFullName)
|
||||
string dir;
|
||||
try
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
dir = CreateTempDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private static void TryRegisterAssembly(ComponentCatalog catalog, Assembly assembly)
|
||||
{
|
||||
// Don't try to index dynamic generated assembly
|
||||
if (assembly.IsDynamic)
|
||||
return;
|
||||
|
||||
if (!CanContainComponents(assembly))
|
||||
return;
|
||||
|
||||
catalog.RegisterAssembly(assembly);
|
||||
}
|
||||
|
||||
private sealed class AssemblyRegistrar : IDisposable
|
||||
{
|
||||
private readonly IHostEnvironment _env;
|
||||
|
||||
public AssemblyRegistrar(IHostEnvironment env, string path)
|
||||
{
|
||||
_env = env;
|
||||
|
||||
RegisterCurrentLoadedAssemblies(_env);
|
||||
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
catch (Exception e)
|
||||
{
|
||||
LoadAssembliesInDir(_env, path, true);
|
||||
path = Path.Combine(path, "AutoLoad");
|
||||
LoadAssembliesInDir(_env, path, true);
|
||||
throw Contracts.ExceptIO(e, "Creating temp directory for extra assembly zip extraction failed: '{0}'", path);
|
||||
}
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomainAssemblyLoad;
|
||||
}
|
||||
try
|
||||
{
|
||||
zip.ExtractToDirectory(dir);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Contracts.ExceptIO(e, "Extracting extra assembly zip failed: '{0}'", path);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomainAssemblyLoad;
|
||||
}
|
||||
|
||||
private void CurrentDomainAssemblyLoad(object sender, AssemblyLoadEventArgs args)
|
||||
{
|
||||
TryRegisterAssembly(_env.ComponentCatalog, args.LoadedAssembly);
|
||||
LoadAssembliesInDir(env, dir, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IDisposable CreateAssemblyRegistrar(IHostEnvironment env, string loadAssembliesPath = null)
|
||||
{
|
||||
Contracts.CheckValue(env, nameof(env));
|
||||
env.CheckValueOrNull(loadAssembliesPath);
|
||||
|
||||
return new AssemblyRegistrar(env, loadAssembliesPath);
|
||||
}
|
||||
|
||||
public static void RegisterCurrentLoadedAssemblies(IHostEnvironment env)
|
||||
{
|
||||
Contracts.CheckValue(env, nameof(env));
|
||||
|
||||
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
TryRegisterAssembly(env.ComponentCatalog, a);
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateTempDirectory()
|
||||
{
|
||||
string dir = GetTempPath();
|
||||
Directory.CreateDirectory(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
private static string GetTempPath()
|
||||
{
|
||||
Guid guid = Guid.NewGuid();
|
||||
return Path.GetFullPath(Path.Combine(Path.GetTempPath(), "MLNET_" + guid.ToString()));
|
||||
}
|
||||
|
||||
private static readonly string[] _filePrefixesToAvoid = new string[] {
|
||||
"api-ms-win",
|
||||
"clr",
|
||||
"coreclr",
|
||||
"dbgshim",
|
||||
"ext-ms-win",
|
||||
"microsoft.bond.",
|
||||
"microsoft.cosmos.",
|
||||
"microsoft.csharp",
|
||||
"microsoft.data.",
|
||||
"microsoft.hpc.",
|
||||
"microsoft.live.",
|
||||
"microsoft.platformbuilder.",
|
||||
"microsoft.visualbasic",
|
||||
"microsoft.visualstudio.",
|
||||
"microsoft.win32",
|
||||
"microsoft.windowsapicodepack.",
|
||||
"microsoft.windowsazure.",
|
||||
"mscor",
|
||||
"msvc",
|
||||
"petzold.",
|
||||
"roslyn.",
|
||||
"sho",
|
||||
"sni",
|
||||
"sqm",
|
||||
"system.",
|
||||
"zlib",
|
||||
};
|
||||
|
||||
private static bool ShouldSkipPath(string path)
|
||||
{
|
||||
string name = Path.GetFileName(path).ToLowerInvariant();
|
||||
switch (name)
|
||||
{
|
||||
case "cpumathnative.dll":
|
||||
case "cqo.dll":
|
||||
case "fasttreenative.dll":
|
||||
case "libiomp5md.dll":
|
||||
case "ldanative.dll":
|
||||
case "libvw.dll":
|
||||
case "matrixinterf.dll":
|
||||
case "microsoft.ml.neuralnetworks.gpucuda.dll":
|
||||
case "mklimports.dll":
|
||||
case "microsoft.research.controls.decisiontrees.dll":
|
||||
case "microsoft.ml.neuralnetworks.sse.dll":
|
||||
case "mklproxynative.dll":
|
||||
case "neuraltreeevaluator.dll":
|
||||
case "optimizationbuilderdotnet.dll":
|
||||
case "parallelcommunicator.dll":
|
||||
case "Microsoft.ML.runtests.dll":
|
||||
case "scopecompiler.dll":
|
||||
case "symsgdnative.dll":
|
||||
case "tbb.dll":
|
||||
case "internallearnscope.dll":
|
||||
case "unmanagedlib.dll":
|
||||
case "vcclient.dll":
|
||||
case "libxgboost.dll":
|
||||
case "zedgraph.dll":
|
||||
case "__scopecodegen__.dll":
|
||||
case "cosmosClientApi.dll":
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var s in _filePrefixesToAvoid)
|
||||
{
|
||||
if (name.StartsWith(s, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void LoadAssembliesInDir(IHostEnvironment env, string dir, bool filter)
|
||||
{
|
||||
if (!Directory.Exists(dir))
|
||||
return;
|
||||
|
||||
// Load all dlls in the given directory.
|
||||
var paths = Directory.EnumerateFiles(dir, "*.dll");
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (filter && ShouldSkipPath(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LoadAssembly(env, path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given an assembly path, load the assembly and register it with the ComponentCatalog.
|
||||
/// </summary>
|
||||
private static Assembly LoadAssembly(IHostEnvironment env, string path)
|
||||
{
|
||||
Assembly assembly = null;
|
||||
try
|
||||
{
|
||||
assembly = Assembly.LoadFrom(path);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (assembly != null)
|
||||
{
|
||||
TryRegisterAssembly(env.ComponentCatalog, assembly);
|
||||
}
|
||||
|
||||
return assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether <paramref name="assembly"/> references the assembly containing LoadableClassAttributeBase,
|
||||
/// and therefore can contain components.
|
||||
/// </summary>
|
||||
private static bool CanContainComponents(Assembly assembly)
|
||||
{
|
||||
var targetFullName = typeof(LoadableClassAttributeBase).Assembly.GetName().FullName;
|
||||
|
||||
bool found = false;
|
||||
foreach (var name in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
if (name.FullName == targetFullName)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private static void TryRegisterAssembly(ComponentCatalog catalog, Assembly assembly)
|
||||
{
|
||||
// Don't try to index dynamic generated assembly
|
||||
if (assembly.IsDynamic)
|
||||
return;
|
||||
|
||||
if (!CanContainComponents(assembly))
|
||||
return;
|
||||
|
||||
catalog.RegisterAssembly(assembly);
|
||||
}
|
||||
|
||||
private sealed class AssemblyRegistrar : IDisposable
|
||||
{
|
||||
private readonly IHostEnvironment _env;
|
||||
|
||||
public AssemblyRegistrar(IHostEnvironment env, string path)
|
||||
{
|
||||
_env = env;
|
||||
|
||||
RegisterCurrentLoadedAssemblies(_env);
|
||||
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
LoadAssembliesInDir(_env, path, true);
|
||||
path = Path.Combine(path, "AutoLoad");
|
||||
LoadAssembliesInDir(_env, path, true);
|
||||
}
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomainAssemblyLoad;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomainAssemblyLoad;
|
||||
}
|
||||
|
||||
private void CurrentDomainAssemblyLoad(object sender, AssemblyLoadEventArgs args)
|
||||
{
|
||||
TryRegisterAssembly(_env.ComponentCatalog, args.LoadedAssembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -4,166 +4,165 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.ML.Runtime
|
||||
namespace Microsoft.ML.Runtime;
|
||||
|
||||
/// <summary>
|
||||
/// This is a token interface that all component factories must implement.
|
||||
/// </summary>
|
||||
public interface IComponentFactory
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>).
|
||||
/// </summary>
|
||||
public interface IComponentFactory<out TComponent> : IComponentFactory
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component when we take one extra parameter (and an <see cref="IHostEnvironment"/>).
|
||||
/// </summary>
|
||||
public interface IComponentFactory<in TArg1, out TComponent> : IComponentFactory
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env, TArg1 argument1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component when we take two extra parameters (and an <see cref="IHostEnvironment"/>).
|
||||
/// </summary>
|
||||
public interface IComponentFactory<in TArg1, in TArg2, out TComponent> : IComponentFactory
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component when we take three extra parameters (and an <see cref="IHostEnvironment"/>).
|
||||
/// </summary>
|
||||
public interface IComponentFactory<in TArg1, in TArg2, in TArg3, out TComponent> : IComponentFactory
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2, TArg3 argument3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A utility class for creating <see cref="IComponentFactory"/> instances.
|
||||
/// </summary>
|
||||
[BestFriend]
|
||||
internal static class ComponentFactoryUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a token interface that all component factories must implement.
|
||||
/// Creates a component factory with no extra parameters (other than an <see cref="IHostEnvironment"/>)
|
||||
/// that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public interface IComponentFactory
|
||||
public static IComponentFactory<TComponent> CreateFromFunction<TComponent>(Func<IHostEnvironment, TComponent> factory)
|
||||
{
|
||||
return new SimpleComponentFactory<TComponent>(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>).
|
||||
/// Creates a component factory when we take one extra parameter (and an
|
||||
/// <see cref="IHostEnvironment"/>) that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public interface IComponentFactory<out TComponent> : IComponentFactory
|
||||
public static IComponentFactory<TArg1, TComponent> CreateFromFunction<TArg1, TComponent>(Func<IHostEnvironment, TArg1, TComponent> factory)
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env);
|
||||
return new SimpleComponentFactory<TArg1, TComponent>(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component when we take one extra parameter (and an <see cref="IHostEnvironment"/>).
|
||||
/// Creates a component factory when we take two extra parameters (and an
|
||||
/// <see cref="IHostEnvironment"/>) that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public interface IComponentFactory<in TArg1, out TComponent> : IComponentFactory
|
||||
public static IComponentFactory<TArg1, TArg2, TComponent> CreateFromFunction<TArg1, TArg2, TComponent>(Func<IHostEnvironment, TArg1, TArg2, TComponent> factory)
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env, TArg1 argument1);
|
||||
return new SimpleComponentFactory<TArg1, TArg2, TComponent>(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component when we take two extra parameters (and an <see cref="IHostEnvironment"/>).
|
||||
/// Creates a component factory when we take three extra parameters (and an
|
||||
/// <see cref="IHostEnvironment"/>) that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public interface IComponentFactory<in TArg1, in TArg2, out TComponent> : IComponentFactory
|
||||
public static IComponentFactory<TArg1, TArg2, TArg3, TComponent> CreateFromFunction<TArg1, TArg2, TArg3, TComponent>(Func<IHostEnvironment, TArg1, TArg2, TArg3, TComponent> factory)
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2);
|
||||
return new SimpleComponentFactory<TArg1, TArg2, TArg3, TComponent>(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An interface for creating a component when we take three extra parameters (and an <see cref="IHostEnvironment"/>).
|
||||
/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
|
||||
/// that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public interface IComponentFactory<in TArg1, in TArg2, in TArg3, out TComponent> : IComponentFactory
|
||||
private sealed class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
|
||||
{
|
||||
TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2, TArg3 argument3);
|
||||
private readonly Func<IHostEnvironment, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public TComponent CreateComponent(IHostEnvironment env)
|
||||
{
|
||||
return _factory(env);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A utility class for creating <see cref="IComponentFactory"/> instances.
|
||||
/// A class for creating a component when we take one extra parameter
|
||||
/// (and an <see cref="IHostEnvironment"/>) that simply wraps a delegate which
|
||||
/// creates the component.
|
||||
/// </summary>
|
||||
[BestFriend]
|
||||
internal static class ComponentFactoryUtils
|
||||
private sealed class SimpleComponentFactory<TArg1, TComponent> : IComponentFactory<TArg1, TComponent>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a component factory with no extra parameters (other than an <see cref="IHostEnvironment"/>)
|
||||
/// that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public static IComponentFactory<TComponent> CreateFromFunction<TComponent>(Func<IHostEnvironment, TComponent> factory)
|
||||
private readonly Func<IHostEnvironment, TArg1, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
|
||||
{
|
||||
return new SimpleComponentFactory<TComponent>(factory);
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a component factory when we take one extra parameter (and an
|
||||
/// <see cref="IHostEnvironment"/>) that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public static IComponentFactory<TArg1, TComponent> CreateFromFunction<TArg1, TComponent>(Func<IHostEnvironment, TArg1, TComponent> factory)
|
||||
public TComponent CreateComponent(IHostEnvironment env, TArg1 argument1)
|
||||
{
|
||||
return new SimpleComponentFactory<TArg1, TComponent>(factory);
|
||||
return _factory(env, argument1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class for creating a component when we take one extra parameter
|
||||
/// (and an <see cref="IHostEnvironment"/>) that simply wraps a delegate which
|
||||
/// creates the component.
|
||||
/// </summary>
|
||||
private sealed class SimpleComponentFactory<TArg1, TArg2, TComponent> : IComponentFactory<TArg1, TArg2, TComponent>
|
||||
{
|
||||
private readonly Func<IHostEnvironment, TArg1, TArg2, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TArg2, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a component factory when we take two extra parameters (and an
|
||||
/// <see cref="IHostEnvironment"/>) that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public static IComponentFactory<TArg1, TArg2, TComponent> CreateFromFunction<TArg1, TArg2, TComponent>(Func<IHostEnvironment, TArg1, TArg2, TComponent> factory)
|
||||
public TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2)
|
||||
{
|
||||
return new SimpleComponentFactory<TArg1, TArg2, TComponent>(factory);
|
||||
return _factory(env, argument1, argument2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class for creating a component when we take three extra parameters
|
||||
/// (and an <see cref="IHostEnvironment"/>) that simply wraps a delegate which
|
||||
/// creates the component.
|
||||
/// </summary>
|
||||
private sealed class SimpleComponentFactory<TArg1, TArg2, TArg3, TComponent> : IComponentFactory<TArg1, TArg2, TArg3, TComponent>
|
||||
{
|
||||
private readonly Func<IHostEnvironment, TArg1, TArg2, TArg3, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TArg2, TArg3, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a component factory when we take three extra parameters (and an
|
||||
/// <see cref="IHostEnvironment"/>) that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
public static IComponentFactory<TArg1, TArg2, TArg3, TComponent> CreateFromFunction<TArg1, TArg2, TArg3, TComponent>(Func<IHostEnvironment, TArg1, TArg2, TArg3, TComponent> factory)
|
||||
public TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2, TArg3 argument3)
|
||||
{
|
||||
return new SimpleComponentFactory<TArg1, TArg2, TArg3, TComponent>(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
|
||||
/// that simply wraps a delegate which creates the component.
|
||||
/// </summary>
|
||||
private sealed class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
|
||||
{
|
||||
private readonly Func<IHostEnvironment, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public TComponent CreateComponent(IHostEnvironment env)
|
||||
{
|
||||
return _factory(env);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class for creating a component when we take one extra parameter
|
||||
/// (and an <see cref="IHostEnvironment"/>) that simply wraps a delegate which
|
||||
/// creates the component.
|
||||
/// </summary>
|
||||
private sealed class SimpleComponentFactory<TArg1, TComponent> : IComponentFactory<TArg1, TComponent>
|
||||
{
|
||||
private readonly Func<IHostEnvironment, TArg1, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public TComponent CreateComponent(IHostEnvironment env, TArg1 argument1)
|
||||
{
|
||||
return _factory(env, argument1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class for creating a component when we take one extra parameter
|
||||
/// (and an <see cref="IHostEnvironment"/>) that simply wraps a delegate which
|
||||
/// creates the component.
|
||||
/// </summary>
|
||||
private sealed class SimpleComponentFactory<TArg1, TArg2, TComponent> : IComponentFactory<TArg1, TArg2, TComponent>
|
||||
{
|
||||
private readonly Func<IHostEnvironment, TArg1, TArg2, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TArg2, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2)
|
||||
{
|
||||
return _factory(env, argument1, argument2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class for creating a component when we take three extra parameters
|
||||
/// (and an <see cref="IHostEnvironment"/>) that simply wraps a delegate which
|
||||
/// creates the component.
|
||||
/// </summary>
|
||||
private sealed class SimpleComponentFactory<TArg1, TArg2, TArg3, TComponent> : IComponentFactory<TArg1, TArg2, TArg3, TComponent>
|
||||
{
|
||||
private readonly Func<IHostEnvironment, TArg1, TArg2, TArg3, TComponent> _factory;
|
||||
|
||||
public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TArg2, TArg3, TComponent> factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public TComponent CreateComponent(IHostEnvironment env, TArg1 argument1, TArg2 argument2, TArg3 argument3)
|
||||
{
|
||||
return _factory(env, argument1, argument2, argument3);
|
||||
}
|
||||
return _factory(env, argument1, argument2, argument3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,20 +4,19 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.ML
|
||||
{
|
||||
/// <summary>
|
||||
/// The base attribute type for all attributes used for extensibility purposes.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public abstract class ExtensionBaseAttribute : Attribute
|
||||
{
|
||||
public string ContractName { get; }
|
||||
namespace Microsoft.ML;
|
||||
|
||||
[BestFriend]
|
||||
private protected ExtensionBaseAttribute(string contractName)
|
||||
{
|
||||
ContractName = contractName;
|
||||
}
|
||||
/// <summary>
|
||||
/// The base attribute type for all attributes used for extensibility purposes.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public abstract class ExtensionBaseAttribute : Attribute
|
||||
{
|
||||
public string ContractName { get; }
|
||||
|
||||
[BestFriend]
|
||||
private protected ExtensionBaseAttribute(string contractName)
|
||||
{
|
||||
ContractName = contractName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,229 +8,228 @@ using System.Reflection;
|
|||
using Microsoft.ML.Internal.Utilities;
|
||||
using Microsoft.ML.Runtime;
|
||||
|
||||
namespace Microsoft.ML
|
||||
namespace Microsoft.ML;
|
||||
|
||||
/// <summary>
|
||||
/// Common signature type with no extra parameters.
|
||||
/// </summary>
|
||||
[BestFriend]
|
||||
internal delegate void SignatureDefault();
|
||||
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||
[BestFriend]
|
||||
internal sealed class LoadableClassAttribute : LoadableClassAttributeBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Common signature type with no extra parameters.
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
[BestFriend]
|
||||
internal delegate void SignatureDefault();
|
||||
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||
[BestFriend]
|
||||
internal sealed class LoadableClassAttribute : LoadableClassAttributeBase
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(Type instType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(null, instType, instType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(Type instType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(null, instType, instType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="loaderType">The class type that contains the construction method</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(Type instType, Type loaderType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(null, instType, loaderType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
public LoadableClassAttribute(Type instType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(null, instType, instType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
public LoadableClassAttribute(Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(null, instType, loaderType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="summary">The description summary of the class type</param>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(string summary, Type instType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(summary, instType, instType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="summary">The description summary of the class type</param>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="loaderType">The class type that contains the construction method</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(string summary, Type instType, Type loaderType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(summary, instType, loaderType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
public LoadableClassAttribute(string summary, Type instType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(summary, instType, instType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
public LoadableClassAttribute(string summary, Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(summary, instType, loaderType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class LoadableClassAttributeBase : Attribute
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="loaderType">The class type that contains the construction method</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(Type instType, Type loaderType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(null, instType, loaderType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
// Note: these properties have private setters to make attribute parsing easier - the values
|
||||
// are all guaranteed to be in the ConstructorArguments of the CustomAttributeData
|
||||
// (no named arguments).
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type that is created/loaded.
|
||||
/// </summary>
|
||||
public Type InstanceType { get; private set; }
|
||||
public LoadableClassAttribute(Type instType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(null, instType, instType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type that contains the construction method, whether static Instance property,
|
||||
/// static Create method, or constructor. Of course, a constructor is only permissible if
|
||||
/// this type derives from InstanceType. This defaults to the same as InstanceType.
|
||||
/// </summary>
|
||||
public Type LoaderType { get; private set; }
|
||||
public LoadableClassAttribute(Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(null, instType, loaderType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The command line arguments object type. This should be null if there isn't one.
|
||||
/// </summary>
|
||||
public Type ArgType { get; private set; }
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="summary">The description summary of the class type</param>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(string summary, Type instType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(summary, instType, instType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This indicates the extra parameter types. It must be a delegate type. The return type should be void.
|
||||
/// The parameter types of the SigType delegate should NOT include the ArgType.
|
||||
/// </summary>
|
||||
public Type[] SigTypes { get; private set; }
|
||||
/// <summary>
|
||||
/// Assembly attribute used to specify that a class is loadable by a machine learning
|
||||
/// host environment, such as TLC
|
||||
/// </summary>
|
||||
/// <param name="summary">The description summary of the class type</param>
|
||||
/// <param name="instType">The class type that is loadable</param>
|
||||
/// <param name="loaderType">The class type that contains the construction method</param>
|
||||
/// <param name="argType">The argument type that the constructor takes (may be null)</param>
|
||||
/// <param name="sigType">The signature of the constructor of this class (in addition to the arguments parameter)</param>
|
||||
/// <param name="userName">The name to use when presenting a list to users</param>
|
||||
/// <param name="loadNames">The names that can be used to load the class, for example, from a command line</param>
|
||||
public LoadableClassAttribute(string summary, Type instType, Type loaderType, Type argType, Type sigType, string userName, params string[] loadNames)
|
||||
: base(summary, instType, loaderType, argType, new[] { sigType }, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note that CtorTypes includes the ArgType (if there is one), and the parameter types of the SigType.
|
||||
/// </summary>
|
||||
public Type[] CtorTypes { get; private set; }
|
||||
public LoadableClassAttribute(string summary, Type instType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(summary, instType, instType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The description summary of the class type.
|
||||
/// </summary>
|
||||
public string Summary { get; private set; }
|
||||
public LoadableClassAttribute(string summary, Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
: base(summary, instType, loaderType, argType, sigTypes, userName, loadNames)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UserName may be null or empty indicating that it should be hidden in UI.
|
||||
/// </summary>
|
||||
public string UserName { get; private set; }
|
||||
public string[] LoadNames { get; private set; }
|
||||
internal abstract class LoadableClassAttributeBase : Attribute
|
||||
{
|
||||
// Note: these properties have private setters to make attribute parsing easier - the values
|
||||
// are all guaranteed to be in the ConstructorArguments of the CustomAttributeData
|
||||
// (no named arguments).
|
||||
|
||||
// REVIEW: This is out of step with the remainder of the class. However, my opinion is that the
|
||||
// LoadableClassAttribute class's design is worth reconsideration: having so many Type and string arguments
|
||||
// be defined *without names* in a constructor has led to enormous confusion.
|
||||
/// <summary>
|
||||
/// The type that is created/loaded.
|
||||
/// </summary>
|
||||
public Type InstanceType { get; private set; }
|
||||
|
||||
// REVIEW: Presumably it would be beneficial to have multiple documents.
|
||||
/// <summary>
|
||||
/// The type that contains the construction method, whether static Instance property,
|
||||
/// static Create method, or constructor. Of course, a constructor is only permissible if
|
||||
/// this type derives from InstanceType. This defaults to the same as InstanceType.
|
||||
/// </summary>
|
||||
public Type LoaderType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This should indicate a path within the <code>doc/public</code> directory next to the TLC
|
||||
/// solution, where the documentation lies. This value will be used as part of a URL, so,
|
||||
/// the path separator should be phrased as '/' forward slashes rather than backslashes.</summary>
|
||||
public string DocName { get; set; }
|
||||
/// <summary>
|
||||
/// The command line arguments object type. This should be null if there isn't one.
|
||||
/// </summary>
|
||||
public Type ArgType { get; private set; }
|
||||
|
||||
protected LoadableClassAttributeBase(string summary, Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
/// <summary>
|
||||
/// This indicates the extra parameter types. It must be a delegate type. The return type should be void.
|
||||
/// The parameter types of the SigType delegate should NOT include the ArgType.
|
||||
/// </summary>
|
||||
public Type[] SigTypes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Note that CtorTypes includes the ArgType (if there is one), and the parameter types of the SigType.
|
||||
/// </summary>
|
||||
public Type[] CtorTypes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The description summary of the class type.
|
||||
/// </summary>
|
||||
public string Summary { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UserName may be null or empty indicating that it should be hidden in UI.
|
||||
/// </summary>
|
||||
public string UserName { get; private set; }
|
||||
public string[] LoadNames { get; private set; }
|
||||
|
||||
// REVIEW: This is out of step with the remainder of the class. However, my opinion is that the
|
||||
// LoadableClassAttribute class's design is worth reconsideration: having so many Type and string arguments
|
||||
// be defined *without names* in a constructor has led to enormous confusion.
|
||||
|
||||
// REVIEW: Presumably it would be beneficial to have multiple documents.
|
||||
|
||||
/// <summary>
|
||||
/// This should indicate a path within the <code>doc/public</code> directory next to the TLC
|
||||
/// solution, where the documentation lies. This value will be used as part of a URL, so,
|
||||
/// the path separator should be phrased as '/' forward slashes rather than backslashes.</summary>
|
||||
public string DocName { get; set; }
|
||||
|
||||
protected LoadableClassAttributeBase(string summary, Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
|
||||
{
|
||||
Contracts.CheckValueOrNull(summary);
|
||||
Contracts.CheckValue(instType, nameof(instType));
|
||||
Contracts.CheckValue(loaderType, nameof(loaderType));
|
||||
Contracts.CheckNonEmpty(sigTypes, nameof(sigTypes));
|
||||
|
||||
if (Utils.Size(loadNames) == 0)
|
||||
loadNames = new string[] { userName };
|
||||
|
||||
if (loadNames.Any(s => string.IsNullOrWhiteSpace(s)))
|
||||
throw Contracts.ExceptEmpty(nameof(loadNames), "LoadableClass loadName parameter can't be empty");
|
||||
|
||||
var sigType = sigTypes[0];
|
||||
Contracts.CheckValue(sigType, nameof(sigTypes));
|
||||
Type[] types;
|
||||
Contracts.CheckParam(sigType.BaseType == typeof(System.MulticastDelegate), nameof(sigTypes), "LoadableClass signature type must be a delegate type");
|
||||
|
||||
var meth = sigType.GetMethod("Invoke");
|
||||
Contracts.CheckParam(meth != null, nameof(sigTypes), "LoadableClass signature type must be a delegate type");
|
||||
Contracts.CheckParam(meth.ReturnType == typeof(void), nameof(sigTypes), "LoadableClass signature type must be a delegate type with void return");
|
||||
|
||||
var parms = meth.GetParameters();
|
||||
int itypeBase = 0;
|
||||
|
||||
if (argType != null)
|
||||
{
|
||||
Contracts.CheckValueOrNull(summary);
|
||||
Contracts.CheckValue(instType, nameof(instType));
|
||||
Contracts.CheckValue(loaderType, nameof(loaderType));
|
||||
Contracts.CheckNonEmpty(sigTypes, nameof(sigTypes));
|
||||
types = new Type[1 + parms.Length];
|
||||
types[itypeBase++] = argType;
|
||||
}
|
||||
else if (parms.Length > 0)
|
||||
types = new Type[parms.Length];
|
||||
else
|
||||
types = Type.EmptyTypes;
|
||||
|
||||
if (Utils.Size(loadNames) == 0)
|
||||
loadNames = new string[] { userName };
|
||||
for (int itype = 0; itype < parms.Length; itype++)
|
||||
{
|
||||
var parm = parms[itype];
|
||||
if ((parm.Attributes & (ParameterAttributes.Out | ParameterAttributes.Retval)) != 0)
|
||||
throw Contracts.Except("Invalid signature parameter attributes");
|
||||
types[itypeBase + itype] = parm.ParameterType;
|
||||
}
|
||||
|
||||
if (loadNames.Any(s => string.IsNullOrWhiteSpace(s)))
|
||||
throw Contracts.ExceptEmpty(nameof(loadNames), "LoadableClass loadName parameter can't be empty");
|
||||
|
||||
var sigType = sigTypes[0];
|
||||
for (int i = 1; i < sigTypes.Length; i++)
|
||||
{
|
||||
sigType = sigTypes[i];
|
||||
Contracts.CheckValue(sigType, nameof(sigTypes));
|
||||
Type[] types;
|
||||
Contracts.CheckParam(sigType.BaseType == typeof(System.MulticastDelegate), nameof(sigTypes), "LoadableClass signature type must be a delegate type");
|
||||
|
||||
var meth = sigType.GetMethod("Invoke");
|
||||
Contracts.Check(sigType.BaseType == typeof(System.MulticastDelegate), "LoadableClass signature type must be a delegate type");
|
||||
|
||||
meth = sigType.GetMethod("Invoke");
|
||||
Contracts.CheckParam(meth != null, nameof(sigTypes), "LoadableClass signature type must be a delegate type");
|
||||
Contracts.CheckParam(meth.ReturnType == typeof(void), nameof(sigTypes), "LoadableClass signature type must be a delegate type with void return");
|
||||
|
||||
var parms = meth.GetParameters();
|
||||
int itypeBase = 0;
|
||||
|
||||
if (argType != null)
|
||||
{
|
||||
types = new Type[1 + parms.Length];
|
||||
types[itypeBase++] = argType;
|
||||
}
|
||||
else if (parms.Length > 0)
|
||||
types = new Type[parms.Length];
|
||||
else
|
||||
types = Type.EmptyTypes;
|
||||
|
||||
parms = meth.GetParameters();
|
||||
Contracts.CheckParam(parms.Length + itypeBase == types.Length, nameof(sigTypes), "LoadableClass signatures must have the same number of parameters");
|
||||
for (int itype = 0; itype < parms.Length; itype++)
|
||||
{
|
||||
var parm = parms[itype];
|
||||
if ((parm.Attributes & (ParameterAttributes.Out | ParameterAttributes.Retval)) != 0)
|
||||
throw Contracts.Except("Invalid signature parameter attributes");
|
||||
types[itypeBase + itype] = parm.ParameterType;
|
||||
throw Contracts.ExceptParam(nameof(sigTypes), "Invalid signature parameter attributes");
|
||||
Contracts.CheckParam(types[itypeBase + itype] == parm.ParameterType, nameof(sigTypes),
|
||||
"LoadableClass signatures must have the same set of parameters");
|
||||
}
|
||||
|
||||
for (int i = 1; i < sigTypes.Length; i++)
|
||||
{
|
||||
sigType = sigTypes[i];
|
||||
Contracts.CheckValue(sigType, nameof(sigTypes));
|
||||
|
||||
Contracts.Check(sigType.BaseType == typeof(System.MulticastDelegate), "LoadableClass signature type must be a delegate type");
|
||||
|
||||
meth = sigType.GetMethod("Invoke");
|
||||
Contracts.CheckParam(meth != null, nameof(sigTypes), "LoadableClass signature type must be a delegate type");
|
||||
Contracts.CheckParam(meth.ReturnType == typeof(void), nameof(sigTypes), "LoadableClass signature type must be a delegate type with void return");
|
||||
parms = meth.GetParameters();
|
||||
Contracts.CheckParam(parms.Length + itypeBase == types.Length, nameof(sigTypes), "LoadableClass signatures must have the same number of parameters");
|
||||
for (int itype = 0; itype < parms.Length; itype++)
|
||||
{
|
||||
var parm = parms[itype];
|
||||
if ((parm.Attributes & (ParameterAttributes.Out | ParameterAttributes.Retval)) != 0)
|
||||
throw Contracts.ExceptParam(nameof(sigTypes), "Invalid signature parameter attributes");
|
||||
Contracts.CheckParam(types[itypeBase + itype] == parm.ParameterType, nameof(sigTypes),
|
||||
"LoadableClass signatures must have the same set of parameters");
|
||||
}
|
||||
}
|
||||
|
||||
InstanceType = instType;
|
||||
LoaderType = loaderType;
|
||||
ArgType = argType;
|
||||
SigTypes = sigTypes;
|
||||
CtorTypes = types;
|
||||
Summary = summary;
|
||||
UserName = userName;
|
||||
LoadNames = loadNames;
|
||||
}
|
||||
|
||||
InstanceType = instType;
|
||||
LoaderType = loaderType;
|
||||
ArgType = argType;
|
||||
SigTypes = sigTypes;
|
||||
CtorTypes = types;
|
||||
Summary = summary;
|
||||
UserName = userName;
|
||||
LoadNames = loadNames;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче