-
Notifications
You must be signed in to change notification settings - Fork 392
/
Copy pathBindingContext.cs
147 lines (124 loc) · 5.21 KB
/
BindingContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.CommandLine.Help;
using System.CommandLine.Invocation;
using System.CommandLine.IO;
using System.CommandLine.Parsing;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
#nullable enable
namespace System.CommandLine.Binding
{
public sealed class BindingContext
{
private IConsole _console;
private readonly Dictionary<Type, ModelBinder> _modelBindersByValueDescriptor = new();
public BindingContext(
ParseResult parseResult,
IConsole? console = default)
{
_console = console ?? new SystemConsole();
ParseResult = parseResult ?? throw new ArgumentNullException(nameof(parseResult));
ServiceProvider = new ServiceProvider(this);
}
public ParseResult ParseResult { get; set; }
internal IConsoleFactory? ConsoleFactory { get; set; }
internal IHelpBuilder HelpBuilder => (IHelpBuilder)ServiceProvider.GetService(typeof(IHelpBuilder))!;
public IConsole Console
{
get
{
if (ConsoleFactory != null)
{
var consoleFactory = ConsoleFactory;
ConsoleFactory = null;
_console = consoleFactory.CreateConsole(this);
}
return _console;
}
}
internal ServiceProvider ServiceProvider { get; }
public void AddModelBinder(ModelBinder binder) =>
_modelBindersByValueDescriptor.Add(binder.ValueDescriptor.ValueType, binder);
public ModelBinder GetModelBinder(IValueDescriptor valueDescriptor)
{
if (_modelBindersByValueDescriptor.TryGetValue(valueDescriptor.ValueType, out ModelBinder binder))
{
return binder;
}
return new ModelBinder(valueDescriptor);
}
public void AddService(Type serviceType, Func<IServiceProvider, object> factory)
{
_ = serviceType ?? throw new ArgumentNullException(nameof(serviceType));
_ = factory ?? throw new ArgumentNullException(nameof(factory));
ServiceProvider.AddService(serviceType, factory);
}
public void AddService<T>(Func<IServiceProvider, T> factory)
{
_ = factory ?? throw new ArgumentNullException(nameof(factory));
ServiceProvider.AddService(typeof(T), s => factory(s));
}
public void AddService(Type serviceType, Type? implementationType = null)
{
_ = serviceType ?? throw new ArgumentNullException(nameof(serviceType));
implementationType ??= serviceType;
object factory(IServiceProvider serviceProvider)
{
var bindingContext =
serviceProvider.GetService(typeof(BindingContext)) as BindingContext
?? this;
var valueDescriptor = new ModelBinder.AnonymousValueDescriptor(implementationType);
var modelBinder = bindingContext.GetModelBinder(valueDescriptor);
return modelBinder.CreateInstance(bindingContext)!;
}
AddService(serviceType, factory);
}
public void AddService<TService, TImplementation>() =>
AddService(typeof(TService), typeof(TImplementation));
public void AddService<T>() => AddService<T, T>();
internal bool TryGetValueSource(
IValueDescriptor valueDescriptor,
[MaybeNullWhen(false)] out IValueSource valueSource)
{
if (ServiceProvider.AvailableServiceTypes.Contains(valueDescriptor.ValueType))
{
valueSource = new ServiceProviderValueSource();
return true;
}
valueSource = default!;
return false;
}
internal bool TryBindToScalarValue(
IValueDescriptor valueDescriptor,
IValueSource valueSource,
Resources resources,
out BoundValue? boundValue)
{
if (valueSource.TryGetValue(valueDescriptor, this, out var value))
{
if (value is null || valueDescriptor.ValueType.IsInstanceOfType(value))
{
boundValue = new BoundValue(value, valueDescriptor, valueSource);
return true;
}
else
{
var parsed = ArgumentConverter.ConvertObject(
valueDescriptor as IArgument ?? new Argument(valueDescriptor.ValueName),
valueDescriptor.ValueType,
value,
resources);
if (parsed is SuccessfulArgumentConversionResult successful)
{
boundValue = new BoundValue(successful.Value, valueDescriptor, valueSource);
return true;
}
}
}
boundValue = default;
return false;
}
}
}