[英]C# set all member of a class to public
是的,這個問題似乎很愚蠢。 但是我怎么能在 C# 中做到這一點? 眾所周知,C++ 很容易。 如果一個班級有10000000名成員,我需要一個一個設置權限嗎?
您不能在 C# 中執行此操作。 該語言要求每個成員單獨設置為公共。
順便說一句,如果你有一個有 10000000 名成員的班級,你都想公開,那么你遇到的問題遠比打字工作要大得多。
每個方法和變量都需要在開始時有自己的公共聲明。 對不起!
如果您有很多需要更改的方法,我建議您使用查找和替換。
如果我在一個班級中有 10000000 名成員
C# 中沒有這樣的功能,但無論如何你不應該設計具有這么多成員的類,因為你違反了單一責任原則。
正確設計您的類,使用良好的關注點分離並保持簡單(KISS),您將不會面臨必須將數千名成員從一種可見性轉變為另一種可見性的問題。
從每個成員都以新行開始的文件中讀取類定義。 然后通過在每一行附加“public”來編寫一個新文件,您可以實現這一點。 只需從文件中刪除一些不需要的公共文件,您就有了您想要的課程。 查看如何在 c# 中讀取和寫入文件http://www.tutorialspoint.com/csharp/csharp_text_files.htm
假設您有某種類文件,我會嘗試使用 RegEx(抱歉,我無法提供示例,因為我不擅長 RegEx)
也許一些插件(用於 VS)有可能做這樣的操作(Resharper 或類似的)
您不能在運行時設置類的修飾符。 如果您嘗試設置類型實例的所有成員或獲取所有成員.. 使用反射。 一個簡單的示例場景是..
你有課..
public class MyFabulousClass {
private object FabulousPropertyMember { get; set; }
// and so on ...
}
並且您希望將其所有屬性成員從類型Object設置為給定值..
foreach (var member in typeof(MyFabulousClass).GetFields( BindingFlags.NonPublic ).Where(i => i.FieldType == typeof(Object)))
{
member.SetValue(instance, default(Object));
// do other stuff..
}
這會將所有非公共成員設置為Object類型的默認值
我不知道您要達到什么目的,但這將使您能夠操縱這些值。 否則,您將不得不編寫自己的運行時編譯東西,它會在運行時更改代碼,但這將非常復雜。
這是一個短暫的節省時間,但仍然節省時間。 與其逐個瀏覽並鍵入每個public
,不如在單擊每個成員前面時按住alt
。 這會在您單擊的每個位置放置一個光標。 在您想要公開的每個成員前面alt+click
ed 后,鍵入public
后跟一個空格,就像在單個成員前面一樣。 這樣一來,您就可以一舉在所有成員面前public
。
我還有一個審美問題,寫了一個小源生成器,所以我現在只需要在class
之前放置一個屬性[GeneratePropertiesForAllPrivateVariables]
和一個partial
,而不是無休止地重復public
關鍵字。
它基本上看起來像這樣:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace MemberAccess
{
[AttributeUsage(AttributeTargets.Class/* ToDo: | System.AttributeTargets.Struct */, AllowMultiple = false, Inherited = false)]
public sealed class GeneratePropertiesForAllPrivateVariablesAttribute : Attribute
{
}
[Generator]
public class GeneratePropertiesForAllPrivateVariables : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
}
public void Execute(GeneratorExecutionContext context)
{
#if DEBUG
if (!Debugger.IsAttached)
{
// Debugger.Launch();
}
#endif
var classesWithAttribute = context.Compilation.SyntaxTrees
.SelectMany(st => st.GetRoot()
.DescendantNodes()
.Where(n => n is ClassDeclarationSyntax)
.Select(n => n as ClassDeclarationSyntax)
.Where(r => r.AttributeLists
.SelectMany(al => al.Attributes)
.Any(a => a.Name.GetText().ToString() == "GeneratePropertiesForAllPrivateVariables")));
foreach (var declaredClass in classesWithAttribute)
{
if (declaredClass.Members.Count > 0)
{
// ToDo: Check for public partial class modifiers here
string className = declaredClass.Identifier.ToString();
var generatedClass = this.GenerateClass(declaredClass);
foreach (var classMember in declaredClass.Members)
{
// is field declaration?
if (classMember.Kind().ToString() == "FieldDeclaration")
{
var fieldDeclaration = (classMember as FieldDeclarationSyntax);
// and is private variable?
if (fieldDeclaration != null
&& fieldDeclaration.Declaration is VariableDeclarationSyntax
&& classMember.Modifiers.Where(token => token.Text == "public").Count() == 0)
{
var variableDeclaration = fieldDeclaration.Declaration as VariableDeclarationSyntax;
var declarator = variableDeclaration.DescendantNodes().Where(n => n is VariableDeclaratorSyntax).First() as VariableDeclaratorSyntax;
if (declarator != null)
{
string privateIdentifier = declarator.Identifier.ToString();
if (!string.IsNullOrEmpty(privateIdentifier))
{
// strip possible 'private' modifier
foreach (var modifier in classMember.Modifiers)
if (modifier.Text == "private")
classMember.Modifiers.Remove(modifier);
// get uppercase identifier for public accessors
string? publicIdentifier = null;
if (char.IsLower(privateIdentifier[0]))
publicIdentifier = privateIdentifier[0].ToString().ToUpper() + privateIdentifier.Substring(1);
else if (privateIdentifier[0] == '_')
publicIdentifier = privateIdentifier[1].ToString().ToUpper() + privateIdentifier.Substring(2);
else if (privateIdentifier.Substring(0, 2) == "m_")
publicIdentifier = privateIdentifier[2].ToString().ToUpper() + privateIdentifier.Substring(3);
if (publicIdentifier != null)
{
// ToDo: didn't gigure out how to replace the private identifier with public one in the declarator
// so using a hack with Sting.Replace in GeneratePropery :-/
this.GeneratePropery(ref generatedClass, classMember.ToString(), privateIdentifier, publicIdentifier);
}
}
}
}
}
}
this.CloseClass(generatedClass);
context.AddSource($"{GetNamespace(declaredClass)}_{className}.g", SourceText.From(generatedClass.ToString(), Encoding.UTF8));
}
}
}
private StringBuilder GenerateClass(ClassDeclarationSyntax c)
{
var sb = new StringBuilder();
sb.Append(@"
using System;
using System.Collections.Generic;
namespace ");
sb.Append(GetNamespace(c));
sb.Append(@"
{
public partial class " + c.Identifier);
sb.Append(@"
{");
return sb;
}
private void GeneratePropery(ref StringBuilder builder, string declaration, /*FieldDeclarationSyntax fds,*/ string privId, string pubId)
{
string replaceIdentifier = declaration.Replace(privId, pubId); // ToDo: make sure that Replace only hits once -- or even better, find out
string removeSemicolon = replaceIdentifier; // how to replace elements of a syntax and pass that as argument.
if (removeSemicolon[removeSemicolon.Length - 1] == ';')
removeSemicolon = removeSemicolon.Substring(0, removeSemicolon.Length - 1);
string decl = $"public {removeSemicolon}";
string getter = $"get => {privId};";
string setter = $"set => {privId} = value;";
builder.AppendLine(@"
" + decl + @"
{
" + getter + @"
" + setter + @"
}");
}
private void CloseClass(StringBuilder generatedClass)
{
generatedClass.Append(
@" }
}");
}
// determine the namespace the class/enum/struct is declared in, if any
private string GetNamespace(BaseTypeDeclarationSyntax syntax)
{
// If we don't have a namespace at all we'll return an empty string
// This accounts for the "default namespace" case
string nameSpace = string.Empty;
// Get the containing syntax node for the type declaration
// (could be a nested type, for example)
SyntaxNode? potentialNamespaceParent = syntax.Parent;
// Keep moving "out" of nested classes etc until we get to a namespace
// or until we run out of parents
while (potentialNamespaceParent != null &&
potentialNamespaceParent is not NamespaceDeclarationSyntax
&& potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax)
{
potentialNamespaceParent = potentialNamespaceParent.Parent;
}
// Build up the final namespace by looping until we no longer have a namespace declaration
if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent)
{
// We have a namespace. Use that as the type
nameSpace = namespaceParent.Name.ToString();
// Keep moving "out" of the namespace declarations until we
// run out of nested namespace declarations
while (true)
{
if (namespaceParent.Parent is not NamespaceDeclarationSyntax parent)
{
break;
}
// Add the outer namespace as a prefix to the final namespace
nameSpace = $"{namespaceParent.Name}.{nameSpace}";
namespaceParent = parent;
}
}
// return the final namespace
return nameSpace;
}
}
}
也許這對 C# 純粹主義者來說是異端,但對我有用。
注意:裝飾類目前仍然需要是public
的和非static
的。
為了您的方便,我還添加了一個GitHub 存儲庫。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.