Skip to content
代码片段 群组 项目
提交 aca31f69 编辑于 作者: Brett V. Forsgren's avatar Brett V. Forsgren 提交者: GitHub
浏览文件

Merge pull request #21539 from heejaechang/noImmutable

removed ImmutableArray from json.net usage. and moved to IList
No related branches found
No related tags found
无相关合并请求
显示
76 个添加48 个删除
......@@ -3,9 +3,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis;
namespace Roslyn.Utilities
{
......@@ -242,6 +244,19 @@ public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> source)
return source.Where((Func<T, bool>)s_notNullTest);
}
public static ImmutableArray<TResult> SelectAsArray<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
if (source == null)
{
return ImmutableArray<TResult>.Empty;
}
var builder = ArrayBuilder<TResult>.GetInstance();
builder.AddRange(source.Select(selector));
return builder.ToImmutableAndFree();
}
public static bool All(this IEnumerable<bool> source)
{
if (source == null)
......
......@@ -257,7 +257,7 @@ await TestInRegularAndScriptAsync(
installerServiceMock.Verify();
}
private Task<ImmutableArray<PackageWithTypeResult>> CreateSearchResult(
private Task<IList<PackageWithTypeResult>> CreateSearchResult(
string packageName, string typeName, ImmutableArray<string> containingNamespaceNames)
{
return CreateSearchResult(new PackageWithTypeResult(
......@@ -265,8 +265,8 @@ private Task<ImmutableArray<PackageWithTypeResult>> CreateSearchResult(
rank: 0, containingNamespaceNames: containingNamespaceNames));
}
private Task<ImmutableArray<PackageWithTypeResult>> CreateSearchResult(params PackageWithTypeResult[] results)
=> Task.FromResult(ImmutableArray.Create(results));
private Task<IList<PackageWithTypeResult>> CreateSearchResult(params PackageWithTypeResult[] results)
=> Task.FromResult<IList<PackageWithTypeResult>>(ImmutableArray.Create(results));
private ImmutableArray<string> CreateNameParts(params string[] parts) => parts.ToImmutableArray();
}
......
......@@ -87,7 +87,7 @@ public async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reason
}
}
private async Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, ImmutableArray<TodoCommentDescriptor> tokens, CancellationToken cancellationToken)
private async Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, IList<TodoCommentDescriptor> tokens, CancellationToken cancellationToken)
{
var service = document.GetLanguageService<ITodoCommentService>();
if (service == null)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
......@@ -122,11 +123,11 @@ public async Task<ImmutableArray<PackageWithTypeResult>> FindPackagesWithTypeAsy
return ImmutableArray<PackageWithTypeResult>.Empty;
}
var results = await session.InvokeAsync<ImmutableArray<PackageWithTypeResult>>(
var results = await session.InvokeAsync<IList<PackageWithTypeResult>>(
nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithTypeAsync),
source, name, arity).ConfigureAwait(false);
return results;
return results.ToImmutableArrayOrEmpty();
}
public async Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAssemblyAsync(
......@@ -139,11 +140,11 @@ public async Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAss
return ImmutableArray<PackageWithAssemblyResult>.Empty;
}
var results = await session.InvokeAsync<ImmutableArray<PackageWithAssemblyResult>>(
var results = await session.InvokeAsync<IList<PackageWithAssemblyResult>>(
nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithAssemblyAsync),
source, assemblyName).ConfigureAwait(false);
return results;
return results.ToImmutableArrayOrEmpty();
}
public async Task<ImmutableArray<ReferenceAssemblyWithTypeResult>> FindReferenceAssembliesWithTypeAsync(
......@@ -156,11 +157,11 @@ public async Task<ImmutableArray<ReferenceAssemblyWithTypeResult>> FindReference
return ImmutableArray<ReferenceAssemblyWithTypeResult>.Empty;
}
var results = await session.InvokeAsync<ImmutableArray<ReferenceAssemblyWithTypeResult>>(
var results = await session.InvokeAsync<IList<ReferenceAssemblyWithTypeResult>>(
nameof(IRemoteSymbolSearchUpdateEngine.FindReferenceAssembliesWithTypeAsync),
name, arity).ConfigureAwait(false);
return results;
return results.ToImmutableArrayOrEmpty();
}
public async Task UpdateContinuouslyAsync(
......
......@@ -239,7 +239,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
installerServiceMock.Verify()
End Function
Private Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As Task(Of ImmutableArray(Of PackageWithTypeResult))
Private Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As Task(Of IList(Of PackageWithTypeResult))
Return CreateSearchResult(New PackageWithTypeResult(
packageName:=packageName,
typeName:=typeName,
......@@ -248,8 +248,8 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
containingNamespaceNames:=nameParts))
End Function
Private Function CreateSearchResult(ParamArray results As PackageWithTypeResult()) As Task(Of ImmutableArray(Of PackageWithTypeResult))
Return Task.FromResult(ImmutableArray.Create(results))
Private Function CreateSearchResult(ParamArray results As PackageWithTypeResult()) As Task(Of IList(Of PackageWithTypeResult))
Return Task.FromResult(Of IList(Of PackageWithTypeResult))(ImmutableArray.Create(results))
End Function
Private Function CreateNameParts(ParamArray parts As String()) As ImmutableArray(Of String)
......
......@@ -17,7 +17,7 @@ internal class CSharpTodoCommentService : AbstractTodoCommentService
private static readonly int s_multilineCommentPostfixLength = "*/".Length;
private const string SingleLineCommentPrefix = "//";
protected override void AppendTodoComments(ImmutableArray<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, SyntaxTrivia trivia, List<TodoComment> todoList)
protected override void AppendTodoComments(IList<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, SyntaxTrivia trivia, List<TodoComment> todoList)
{
if (PreprocessorHasComment(trivia))
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeActions;
......@@ -19,7 +20,7 @@ internal class AddImportFixData
/// May be empty for fixes that don't need to add an import and only do something like
/// add a project/metadata reference.
/// </summary>
public ImmutableArray<TextChange> TextChanges { get; }
public IList<TextChange> TextChanges { get; }
/// <summary>
/// String to display in the lightbulb menu.
......@@ -29,7 +30,7 @@ internal class AddImportFixData
/// <summary>
/// Tags that control what glyph is displayed in the lightbulb menu.
/// </summary>
public ImmutableArray<string> Tags { get; private set; }
public IList<string> Tags { get; private set; }
/// <summary>
/// The priority this item should have in the lightbulb list.
......
......@@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
{
......@@ -44,9 +45,9 @@ protected AddImportCodeAction(
FixData = fixData;
Title = fixData.Title;
Tags = fixData.Tags;
Tags = fixData.Tags.ToImmutableArrayOrEmpty();
Priority = fixData.Priority;
_textChanges = fixData.TextChanges;
_textChanges = fixData.TextChanges.ToImmutableArrayOrEmpty();
}
protected async Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToken)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
......@@ -19,12 +20,12 @@ private async Task<ImmutableArray<AddImportFixData>> GetFixesInRemoteProcessAsyn
string diagnosticId, bool placeSystemNamespaceFirst,
bool searchReferenceAssemblies, ImmutableArray<PackageSource> packageSources)
{
var result = await session.InvokeAsync<ImmutableArray<AddImportFixData>>(
var result = await session.InvokeAsync<IList<AddImportFixData>>(
nameof(IRemoteAddImportFeatureService.GetFixesAsync),
document.Id, span, diagnosticId, placeSystemNamespaceFirst,
searchReferenceAssemblies, packageSources).ConfigureAwait(false);
return result;
return result.AsImmutableOrEmpty();
}
/// <summary>
......@@ -56,7 +57,7 @@ public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirec
throw new NotImplementedException();
}
public async Task<ImmutableArray<PackageWithTypeResult>> FindPackagesWithTypeAsync(
public async Task<IList<PackageWithTypeResult>> FindPackagesWithTypeAsync(
string source, string name, int arity)
{
var result = await _symbolSearchService.FindPackagesWithTypeAsync(
......@@ -65,7 +66,7 @@ public async Task<ImmutableArray<PackageWithTypeResult>> FindPackagesWithTypeAsy
return result;
}
public async Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAssemblyAsync(
public async Task<IList<PackageWithAssemblyResult>> FindPackagesWithAssemblyAsync(
string source, string name)
{
var result = await _symbolSearchService.FindPackagesWithAssemblyAsync(
......@@ -74,7 +75,7 @@ public async Task<ImmutableArray<PackageWithAssemblyResult>> FindPackagesWithAss
return result;
}
public async Task<ImmutableArray<ReferenceAssemblyWithTypeResult>> FindReferenceAssembliesWithTypeAsync(
public async Task<IList<ReferenceAssemblyWithTypeResult>> FindReferenceAssembliesWithTypeAsync(
string name, int arity)
{
var result = await _symbolSearchService.FindReferenceAssembliesWithTypeAsync(
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Packaging;
......@@ -9,8 +10,8 @@ namespace Microsoft.CodeAnalysis.AddImport
{
internal interface IRemoteAddImportFeatureService
{
Task<ImmutableArray<AddImportFixData>> GetFixesAsync(
Task<IList<AddImportFixData>> GetFixesAsync(
DocumentId documentId, TextSpan span, string diagnosticId, bool placeSystemNamespaceFirst,
bool searchReferenceAssemblies, ImmutableArray<PackageSource> packageSources);
bool searchReferenceAssemblies, IList<PackageSource> packageSources);
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
......@@ -87,7 +88,7 @@ private async Task FindReferenceAssemblyTypeReferencesAsync(
cancellationToken.ThrowIfCancellationRequested();
var results = await _symbolSearchService.FindReferenceAssembliesWithTypeAsync(
name, arity, cancellationToken).ConfigureAwait(false);
if (results.IsDefault)
if (results == null)
{
return;
}
......@@ -118,7 +119,7 @@ private async Task FindNugetTypeReferencesAsync(
cancellationToken.ThrowIfCancellationRequested();
var results = await _symbolSearchService.FindPackagesWithTypeAsync(
source.Name, name, arity, cancellationToken).ConfigureAwait(false);
if (results.IsDefault)
if (results == null)
{
return;
}
......@@ -160,7 +161,7 @@ private async Task HandleReferenceAssemblyReferenceAsync(
var desiredName = GetDesiredName(isAttributeSearch, result.TypeName);
allReferences.Add(new AssemblyReference(
_owner, new SearchResult(desiredName, nameNode, result.ContainingNamespaceNames, weight), result));
_owner, new SearchResult(desiredName, nameNode, result.ContainingNamespaceNames.ToReadOnlyList(), weight), result));
}
private void HandleNugetReference(
......@@ -174,7 +175,7 @@ private void HandleNugetReference(
{
var desiredName = GetDesiredName(isAttributeSearch, result.TypeName);
allReferences.Add(new PackageReference(_owner,
new SearchResult(desiredName, nameNode, result.ContainingNamespaceNames, weight),
new SearchResult(desiredName, nameNode, result.ContainingNamespaceNames.ToReadOnlyList(), weight),
source, result.PackageName, result.Version));
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
......@@ -7,6 +8,6 @@ namespace Microsoft.CodeAnalysis.DesignerAttributes
{
internal interface IRemoteDesignerAttributeService
{
Task<ImmutableArray<DesignerAttributeDocumentData>> ScanDesignerAttributesAsync(ProjectId projectId);
Task<IList<DesignerAttributeDocumentData>> ScanDesignerAttributesAsync(ProjectId projectId);
}
}
\ No newline at end of file
......@@ -48,7 +48,7 @@ public async Task<ImmutableArray<DocumentHighlights>> GetDocumentHighlightsAsync
return (succeeded: false, ImmutableArray<DocumentHighlights>.Empty);
}
var result = await session.InvokeAsync<ImmutableArray<SerializableDocumentHighlights>>(
var result = await session.InvokeAsync<IList<SerializableDocumentHighlights>>(
nameof(IRemoteDocumentHighlights.GetDocumentHighlightsAsync),
document.Id,
position,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
......@@ -8,14 +9,14 @@ namespace Microsoft.CodeAnalysis.DocumentHighlighting
{
internal interface IRemoteDocumentHighlights
{
Task<ImmutableArray<SerializableDocumentHighlights>> GetDocumentHighlightsAsync(
Task<IList<SerializableDocumentHighlights>> GetDocumentHighlightsAsync(
DocumentId documentId, int position, DocumentId[] documentIdsToSearch);
}
internal struct SerializableDocumentHighlights
{
public DocumentId DocumentId;
public ImmutableArray<HighlightSpan> HighlightSpans;
public IList<HighlightSpan> HighlightSpans;
public DocumentHighlights Rehydrate(Solution solution)
=> new DocumentHighlights(solution.GetDocument(DocumentId), HighlightSpans.ToImmutableArray());
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.NavigateTo
{
......@@ -12,7 +14,7 @@ internal abstract partial class AbstractNavigateToSearchService
private async Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentInRemoteProcessAsync(
RemoteHostClient.Session session, Document document, string searchPattern, CancellationToken cancellationToken)
{
var serializableResults = await session.InvokeAsync<ImmutableArray<SerializableNavigateToSearchResult>>(
var serializableResults = await session.InvokeAsync<IList<SerializableNavigateToSearchResult>>(
nameof(IRemoteNavigateToSearchService.SearchDocumentAsync),
document.Id, searchPattern).ConfigureAwait(false);
......@@ -22,7 +24,7 @@ private async Task<ImmutableArray<INavigateToSearchResult>> SearchDocumentInRemo
private async Task<ImmutableArray<INavigateToSearchResult>> SearchProjectInRemoteProcessAsync(
RemoteHostClient.Session session, Project project, string searchPattern, CancellationToken cancellationToken)
{
var serializableResults = await session.InvokeAsync<ImmutableArray<SerializableNavigateToSearchResult>>(
var serializableResults = await session.InvokeAsync<IList<SerializableNavigateToSearchResult>>(
nameof(IRemoteNavigateToSearchService.SearchProjectAsync),
project.Id, searchPattern).ConfigureAwait(false);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
......@@ -8,7 +9,7 @@ namespace Microsoft.CodeAnalysis.NavigateTo
{
internal interface IRemoteNavigateToSearchService
{
Task<ImmutableArray<SerializableNavigateToSearchResult>> SearchDocumentAsync(DocumentId documentId, string searchPattern);
Task<ImmutableArray<SerializableNavigateToSearchResult>> SearchProjectAsync(ProjectId projectId, string searchPattern);
Task<IList<SerializableNavigateToSearchResult>> SearchDocumentAsync(DocumentId documentId, string searchPattern);
Task<IList<SerializableNavigateToSearchResult>> SearchProjectAsync(ProjectId projectId, string searchPattern);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.NavigateTo;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote
{
......@@ -17,7 +19,7 @@ internal class SerializableNavigateToSearchResult
public NavigateToMatchKind MatchKind;
public bool IsCaseSensitive;
public string Name;
public ImmutableArray<TextSpan> NameMatchSpans;
public IList<TextSpan> NameMatchSpans;
public string SecondarySort;
public string Summary;
......@@ -82,7 +84,7 @@ internal class SerializableNavigableItem
{
public Glyph Glyph;
public ImmutableArray<TaggedText> DisplayTaggedParts;
public IList<TaggedText> DisplayTaggedParts;
public bool DisplayFileLocation;
......@@ -91,7 +93,7 @@ internal class SerializableNavigableItem
public DocumentId Document;
public TextSpan SourceSpan;
ImmutableArray<SerializableNavigableItem> ChildItems;
public IList<SerializableNavigableItem> ChildItems;
public static SerializableNavigableItem Dehydrate(INavigableItem item)
{
......
......@@ -20,9 +20,9 @@ internal abstract class AbstractTodoCommentService : ITodoCommentService
protected abstract string GetNormalizedText(string message);
protected abstract int GetCommentStartingIndex(string message);
protected abstract void AppendTodoComments(ImmutableArray<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, SyntaxTrivia trivia, List<TodoComment> todoList);
protected abstract void AppendTodoComments(IList<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, SyntaxTrivia trivia, List<TodoComment> todoList);
public async Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, ImmutableArray<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken)
public async Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, IList<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken)
{
// same service run in both inproc and remote host, but remote host will not have RemoteHostClient service,
// so inproc one will always run
......@@ -40,7 +40,7 @@ public async Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, Im
}
private async Task<IList<TodoComment>> GetTodoCommentsInRemoteHostAsync(
RemoteHostClient client, Document document, ImmutableArray<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken)
RemoteHostClient client, Document document, IList<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken)
{
return await client.RunCodeAnalysisServiceOnRemoteHostAsync<IList<TodoComment>>(
document.Project.Solution, nameof(IRemoteTodoCommentService.GetTodoCommentsAsync),
......@@ -48,7 +48,7 @@ private async Task<IList<TodoComment>> GetTodoCommentsInRemoteHostAsync(
}
private async Task<IList<TodoComment>> GetTodoCommentsInCurrentProcessAsync(
Document document, ImmutableArray<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken)
Document document, IList<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -78,7 +78,7 @@ private bool ContainsComments(SyntaxTrivia trivia)
return PreprocessorHasComment(trivia) || IsSingleLineComment(trivia) || IsMultilineComment(trivia);
}
protected void AppendTodoCommentInfoFromSingleLine(ImmutableArray<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, string message, int start, List<TodoComment> todoList)
protected void AppendTodoCommentInfoFromSingleLine(IList<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, string message, int start, List<TodoComment> todoList)
{
var index = GetCommentStartingIndex(message);
if (index >= message.Length)
......@@ -110,7 +110,7 @@ protected void AppendTodoCommentInfoFromSingleLine(ImmutableArray<TodoCommentDes
}
}
protected void ProcessMultilineComment(ImmutableArray<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, SyntaxTrivia trivia, int postfixLength, List<TodoComment> todoList)
protected void ProcessMultilineComment(IList<TodoCommentDescriptor> commentDescriptors, SyntacticDocument document, SyntaxTrivia trivia, int postfixLength, List<TodoComment> todoList)
{
// this is okay since we know it is already alive
var text = document.Text;
......
......@@ -11,6 +11,6 @@ namespace Microsoft.CodeAnalysis.TodoComments
/// </summary>
internal interface IRemoteTodoCommentService
{
Task<IList<TodoComment>> GetTodoCommentsAsync(DocumentId documentId, ImmutableArray<TodoCommentDescriptor> commentDescriptors);
Task<IList<TodoComment>> GetTodoCommentsAsync(DocumentId documentId, IList<TodoCommentDescriptor> commentDescriptors);
}
}
......@@ -42,6 +42,6 @@ public TodoComment(TodoCommentDescriptor descriptor, string message, int positio
internal interface ITodoCommentService : ILanguageService
{
Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, ImmutableArray<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken);
Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, IList<TodoCommentDescriptor> commentDescriptors, CancellationToken cancellationToken);
}
}
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册