[英]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.