C# 如何访问其他类的私有成员?
我对C并不陌生,但没有Java那么丰富的经验。 正如您所知,在Java中,我们可以从外部类访问所有私有成员。 所以我在C#中也尝试了同样的方法,因为我有一些字段和方法只需要从我的插件库中访问,而不希望它显示给用户。一个简单的例子就是这样C# 如何访问其他类的私有成员?,c#,field,private,C#,Field,Private,我对C并不陌生,但没有Java那么丰富的经验。 正如您所知,在Java中,我们可以从外部类访问所有私有成员。 所以我在C#中也尝试了同样的方法,因为我有一些字段和方法只需要从我的插件库中访问,而不希望它显示给用户。一个简单的例子就是这样 public static class StaticClass { public class InstanceClass { private int oldValue; public int Value; }
public static class StaticClass {
public class InstanceClass {
private int oldValue;
public int Value;
}
public static void Backup(InstanceClass ic) {
ic.oldValue = ic.Value;
}
public static void Restore(InstanceClass ic) {
ic.Value = ic.oldValue;
}
}
如果我将oldValue字段公开,那么当最终用户使用插件时,它将变得混乱和肮脏。它不必是一个内部类或某种特定的形式。我只想知道是否有任何方法可以仅由我控制或访问同一程序集中其他静态类中实例的私有成员。仅允许在程序集中访问,请使用
内部修饰符
public class InstanceClass {
internal int oldValue;
public int Value;
}
您可以使用内部
访问修饰符,请参阅
内部仅从部件内部可见
示例:您是否尝试将其设置为“内部”?它将在同一个dll中可用,但不在外部dll中可用
public class InstanceClass {
internal int oldValue;
public int Value;
}
从技术上讲,您可以使用反射(如果您坚持使用private
字段和静态类方法):
然而,一个更好的方法是将访问修饰符从private
更改为internal
:
public class InstanceClass {
internal int oldValue;
public int Value;
}
更好的解决方案是将Backup
和Restore
方法移动到InstanceClass
:
public class InstanceClass {
private int oldValue;
public int Value;
public void Backup() {
oldValue = Value;
}
public void Restore() {
Value = oldValue;
}
}
这在C#中是不可能的。容器类对嵌套类没有特殊访问权限
您可以从嵌套类访问容器的私有成员,但不能从嵌套类访问容器的私有成员。您试图使用的模式根本没有在C#中使用-这违反了成员可访问性。有一些黑客将Java模式强加于C#(使用反射或滥用接口),但它们只是这些黑客
“最干净”的方法可能如下所示:
public static class StaticClass
{
private interface IInstanceClassInternal
{
int OldValue { get; set; }
}
public sealed class InstanceClass : IInstanceClassInternal
{
int IInstanceClassInternal.OldValue { get; set; }
public int Value;
}
public static void Backup(InstanceClass ic)
{
((IInstanceClassInternal)ic).OldValue = ic.Value;
}
public static void Restore(InstanceClass ic)
{
ic.Value = ((IInstanceClassInternal)ic).OldValue;
}
}
很明显,您正试图用C语言编写Java——模式、编码风格。。。那可能是个坏主意。这些静态方法可能应该是扩展方法。“对象中隐藏的功能”与C#的OOP概念不太相符——你的父母不应该自由访问你的内脏,它应该真正拥有与其他人相同的公共界面。毕竟,这就是LSP的全部要点——这种紧密耦合对于任何可扩展性来说都是相当棘手的。如果您想让StaticClass
与InstanceClass
混为一谈,那么首先为什么要将StaticClass
与InstanceClass
分开呢?只需将备份
和还原
作为InstanceClass
的公共成员,甚至是接口的一部分(如果您想对InstanceClass
的用户“隐藏”它,甚至可以通过显式实现).此字段oldValue
是StaticClass
和InstanceClass
的实现细节。让我们制作InstanceClass
一个StaticClass
的实现细节,并将接口StaticClass.IInstance
导出到外部客户端:
public static class StaticClass {
public interface IInstance {
int Value { get; set; }
}
private class InstanceClass: IInstance {
public int oldValue;
public Value { get; set; }
}
// Static class becomes responsible for handing out `IInstance` objects
public static IInstance GetInstance() {
return new InstanceClass();
}
public static void Backup(IInstance i) {
if (i is InstanceClass ic) {
ic.oldValue = ic.Value;
}
else {
throw new InvallidOperationException("Can only Backup IInstance objects that were created by GetInstance");
}
}
public static void Restore(IInstance i) {
if (I is InstanceClass ic)
{
ic.Value = ic.oldValue;
}
else {
throw new InvallidOperationException("Can only Restore IInstance objects that were created by GetInstance");
}
}
这个解决方案与另一个类似。但它不是使用接口导出私有数据,而是使用接口限制公共可用数据;在我看来,这是一个更干净的设计,惊喜更少。
它确实将值
从字段更改为属性;因此,当您确实需要一个字段时,此模式不起作用
OP示例中的静态类使它有点尴尬,并且有更好的解决方案,但是想象一下在一个常规类中,可能在存储库中。在存储库中工作时,如果设置了存储库中项目的属性,则应通知观察者,并且不希望项目包含对存储库或存储库观察者的引用,这会导致我搜索导致我访问的项目
我打算按如下方式解决这个问题:
public class Repo
{
public interface IItem
{
int Id { get; }
string MyProperty { get; }
}
private class Item
{
public int Id { get; }
public string MyProperty { get; private set; }
public bool TrySetMyProperty(string newValue)
{
if (!Equals(MyProperty, newValue) &&
IsPreconditionValid())
{
MyProperty = newValue;
return true;
}
else
{
return false;
}
IsPreconditionValid() => true;
}
}
public event EventHandler<EventArgs> OnChanged;
private readonly ConcurrentDictionary<int, Item> items = new ConcurrentDictionary<int, Item>();
public IItem GetOrCreateItemById(int id)
{
bool changed = false;
IItem result = items.GetOrAdd(int, CreateItem);
if (changed)
{
OnChanged?.Invoke(this, EventArgs.Empty);
}
return result;
IItem CreateItem(int key)
{
changed = true;
return new Item() { Id = key };
}
}
public bool TrySetItemMyProperty(int id, string newValue)
{
if (items.TryGet(id, out Item i))
{
if (i.TrySetMyProperty(newValue))
{
OnChanged?.Invoke(this, EventArgs.Empty);
return true;
}
}
return false;
}
}
公共类回购
{
公共接口项
{
int Id{get;}
字符串MyProperty{get;}
}
私人类项目
{
公共int Id{get;}
公共字符串MyProperty{get;private set;}
公共bool TrySetMyProperty(字符串newValue)
{
如果(!等于(MyProperty,newValue)&&
IsPreconditionValid())
{
MyProperty=newValue;
返回true;
}
其他的
{
返回false;
}
IsPreconditionValid()=>true;
}
}
公共事件事件处理程序已更改;
私有只读ConcurrentDictionary项=新建ConcurrentDictionary();
公共IItem GetOrCreateItemById(int id)
{
bool-changed=false;
IItem result=items.GetOrAdd(int,CreateItem);
如果(更改)
{
OnChanged?.Invoke(此为EventArgs.Empty);
}
返回结果;
IItem CreateItem(int键)
{
更改=正确;
返回新项(){Id=key};
}
}
公共bool TrySetItemMyProperty(int-id,字符串newValue)
{
if(项目TryGet(id,超出项目i))
{
if(i.TrySetMyProperty(newValue))
{
OnChanged?.Invoke(此为EventArgs.Empty);
返回true;
}
}
返回false;
}
}
只是想知道:这里的一切都是静态的,但您的InstanceClass不是?如果C#与Java类似,那么一些静态上下文应该如何访问非静态内部?答案是,您需要使用“internal”作为访问修饰符。然后,只能从程序集内部的类访问。@ GhostCat,对于C语言中嵌套类,它更像C++而不是java。Java没有静态外部类,对吗?感谢所有在这里写了答案或评论的人。我现在很惭愧。。这是一个非常基本和愚蠢的问题。非常感谢你的提醒。对那些
public class Repo
{
public interface IItem
{
int Id { get; }
string MyProperty { get; }
}
private class Item
{
public int Id { get; }
public string MyProperty { get; private set; }
public bool TrySetMyProperty(string newValue)
{
if (!Equals(MyProperty, newValue) &&
IsPreconditionValid())
{
MyProperty = newValue;
return true;
}
else
{
return false;
}
IsPreconditionValid() => true;
}
}
public event EventHandler<EventArgs> OnChanged;
private readonly ConcurrentDictionary<int, Item> items = new ConcurrentDictionary<int, Item>();
public IItem GetOrCreateItemById(int id)
{
bool changed = false;
IItem result = items.GetOrAdd(int, CreateItem);
if (changed)
{
OnChanged?.Invoke(this, EventArgs.Empty);
}
return result;
IItem CreateItem(int key)
{
changed = true;
return new Item() { Id = key };
}
}
public bool TrySetItemMyProperty(int id, string newValue)
{
if (items.TryGet(id, out Item i))
{
if (i.TrySetMyProperty(newValue))
{
OnChanged?.Invoke(this, EventArgs.Empty);
return true;
}
}
return false;
}
}