-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathUtilities.cs
More file actions
164 lines (150 loc) · 7.63 KB
/
Copy pathUtilities.cs
File metadata and controls
164 lines (150 loc) · 7.63 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// <copyright file="Utilities.cs" company="Microsoft Corporation">
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt in the project root for license information.
// </copyright>
#pragma warning disable SA1314 // Type parameter names should begin with T
namespace Microsoft.VisualStudio.Setup
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Setup.Configuration;
/// <summary>
/// Utility methods.
/// </summary>
internal static class Utilities
{
/// <summary>
/// Gets an empty <see cref="ReadOnlyCollection{T}"/>.
/// </summary>
/// <typeparam name="T">The type of element.</typeparam>
/// <returns>An empty <see cref="ReadOnlyCollection{T}"/>.</returns>
public static ReadOnlyCollection<T> EmptyReadOnlyCollection<T>()
{
return EmptyReadOnlyCollectionContainer<T>.Instance;
}
/// <summary>
/// Gets an <see cref="IEnumerable{T}"/> of adapted packages from type <typeparamref name="T"/> to type <typeparamref name="R"/>.
/// </summary>
/// <typeparam name="T">The type of the package reference to adapt.</typeparam>
/// <typeparam name="R">The adapted type of the package reference.</typeparam>
/// <param name="action">A method that gets an <see cref="IEnumerable{T}"/> of package reference of type <typeparamref name="T"/>.</param>
/// <param name="creator">A method that creates an adapted reference of type <typeparamref name="R"/>.</param>
/// <returns>An <see cref="IEnumerable{T}"/> of adapted packages. This enumeration may yield zero results.</returns>
/// <exception cref="ArgumentNullException"><paramref name="action"/> or <paramref name="creator"/> is null.</exception>
public static IEnumerable<R> GetAdaptedPackages<T, R>(Func<IEnumerable<T>> action, Func<T, R> creator)
where T : ISetupPackageReference
where R : PackageReference
{
Validate.NotNull(action, nameof(action));
Validate.NotNull(creator, nameof(creator));
return YieldAdaptedPackages(action, creator);
}
/// <summary>
/// Tries to convert the string representation of a version number to an equivalent System.Version object,
/// and returns a value that indicates whether the conversion succeeded.
/// </summary>
/// <param name="input">A string that contains a version number to convert.</param>
/// <param name="result">
/// When this method returns, contains the System.Version equivalent of the number that is contained in input,
/// if the conversion succeeded. If the conversion failed, or if input is null or System.String.Empty,
/// result is null when the method returns.
/// </param>
/// <returns>true if the input parameter was converted successfully; otherwise, false.</returns>
public static bool TryParseVersion(string input, out Version result)
{
if (string.IsNullOrEmpty(input))
{
result = null;
return false;
}
try
{
result = new Version(input);
return true;
}
catch
{
result = null;
return false;
}
}
/// <summary>
/// Sets the given <paramref name="property"/> if the <paramref name="action"/> does not throw a <see cref="COMException"/> for 0x80070490.
/// </summary>
/// <typeparam name="T">The type of the property to set.</typeparam>
/// <param name="property">A reference to the property to set.</param>
/// <param name="propertyName">The name of the property for diagnostic purposes.</param>
/// <param name="action">A method that returns the value of the property to set.</param>
/// <param name="error">Optional error handler that accepts the name of the property.</param>
/// <exception cref="ArgumentException"><paramref name="propertyName"/> is an empty string.</exception>
/// <exception cref="ArgumentNullException"><paramref name="propertyName"/> or <paramref name="action"/> is null.</exception>
public static void TrySet<T>(ref T property, string propertyName, Func<T> action, Action<string> error = null)
{
Validate.NotNullOrEmpty(propertyName, nameof(propertyName));
Validate.NotNull(action, nameof(action));
try
{
property = action.Invoke();
}
catch (COMException ex) when (ex.ErrorCode == NativeMethods.E_NOTFOUND)
{
error?.Invoke(propertyName);
}
}
/// <summary>
/// Sets the given package reference collection <paramref name="property"/> if the <paramref name="action"/> does not throw a <see cref="COMException"/> for 0x80070490.
/// </summary>
/// <typeparam name="T">The type of the package reference to adapt.</typeparam>
/// <typeparam name="R">The adapted type of the package reference.</typeparam>
/// <param name="property">A reference to the property to set.</param>
/// <param name="propertyName">The name of the property for diagnostic purposes.</param>
/// <param name="action">A method that returns the value of the property to set.</param>
/// <param name="creator">A method that creates the adapted reference type.</param>
/// <param name="error">Optional error handler that accepts the name of the property.</param>
/// <returns>A <see cref="ReadOnlyCollection{T}"/> containing the adapted package references. This collection may be empty.</returns>
/// <exception cref="ArgumentException"><paramref name="propertyName"/> is an empty string.</exception>
/// <exception cref="ArgumentNullException">One or more parameters is null.</exception>
public static ReadOnlyCollection<R> TrySetCollection<T, R>(
ref IList<R> property,
string propertyName,
Func<IEnumerable<T>> action,
Func<T, R> creator,
Action<string> error = null)
where T : ISetupPackageReference
where R : PackageReference
{
Validate.NotNullOrEmpty(propertyName, nameof(propertyName));
Validate.NotNull(action, nameof(action));
Validate.NotNull(creator, nameof(creator));
var packages = GetAdaptedPackages(action, creator);
TrySet(ref property, propertyName, packages.ToList, error);
if (property != null && property.Any())
{
return new ReadOnlyCollection<R>(property);
}
return EmptyReadOnlyCollection<R>();
}
private static IEnumerable<R> YieldAdaptedPackages<T, R>(Func<IEnumerable<T>> action, Func<T, R> creator)
{
var references = action?.Invoke();
if (references != null)
{
foreach (var reference in references)
{
if (reference != null)
{
yield return creator(reference);
}
}
}
}
private class EmptyReadOnlyCollectionContainer<T>
{
public static readonly ReadOnlyCollection<T> Instance = new ReadOnlyCollection<T>(new T[0]);
}
}
}
#pragma warning restore SA1314 // Type parameter names should begin with T