C# C中友元类用例的变通方法#
考虑以下代码模式:C# C中友元类用例的变通方法#,c#,.net,C#,.net,考虑以下代码模式: // Each foo keeps a reference to its manager class Foo { private FooManager m_manager; } // Manager keeps a list of all foos class FooManager { private List<Foo> m_foos; } //每个foo都保留对其管理器的引用 福班 { 私人餐饮部经理; } //经理保留所有食物的清单 班级经
// Each foo keeps a reference to its manager
class Foo
{
private FooManager m_manager;
}
// Manager keeps a list of all foos
class FooManager
{
private List<Foo> m_foos;
}
//每个foo都保留对其管理器的引用
福班
{
私人餐饮部经理;
}
//经理保留所有食物的清单
班级经理
{
私人名单m_foos;
}
问题:如果不公开一些私密信息(并冒着有人将列表与实际的Foo解除同步的风险),就无法创建新Foo并更新FooManager中的m_foos列表和新Foo实例中的m_manager引用
例如,可以在Foo中实现构造函数Foo(FooManager)。它可以设置m_manager引用,但无法访问m_foos列表。或者可以在管理器中实现CreateFoo()方法。它可以访问m_foos列表,但无法在Foo中设置m_管理器
在C++中,人们会明显地声明FoMaNever是Foo的朋友来表达设计意图,但这在C语言中是不可能的。我也知道我可以让Foo成为FooManager的一个内部类来获得访问权限,但这也不是一个解决方案(如果Foo可以属于多个manager类呢?)
顺便说一句,我知道.NET中的“内部”访问,但它要求Foo和FooManager单独生活在一个单独的程序集中,这是不可接受的
在不公开私人资料的情况下,有什么解决办法吗?如果我理解正确:
public abstract class FooBus
{
protected static FooBus m_bus;
}
public sealed class Foo : FooBus
{
private FooManager m_manager;
public Foo(FooManager fm)
{
if (fm == null)
{
throw new ArgumentNullException("Use FooManager.CreateFoo()");
}
if (m_bus != fm)
{
throw new ArgumentException("Use FooManager.CreateFoo()");
}
m_manager = fm;
}
}
public class FooManager : FooBus
{
private List<Foo> m_foos = new List<Foo>();
public Foo CreateFoo()
{
m_bus = this;
Foo f = new Foo(this);
m_foos.Add(f);
m_bus = null;
return f;
}
}
公共抽象类FooBus
{
受保护的静态FooBus m_总线;
}
公众密封等级Foo:FooBus
{
私人餐饮部经理;
公共食品部(食品经理fm)
{
如果(fm==null)
{
抛出新ArgumentNullException(“使用FooManager.CreateFoo()”);
}
如果(m_总线!=fm)
{
抛出新ArgumentException(“使用FooManager.CreateFoo()”);
}
m_manager=fm;
}
}
公共类FooManager:FooBus
{
私有列表m_foos=新列表();
public Foo CreateFoo()
{
m_bus=这个;
Foo f=新的Foo(本);
m_foos.Add(f);
m_总线=零;
返回f;
}
}
拥有一个基类怎么样:
class FooBase
{
protected static readonly Dictionary<Foo,FooManager> _managerMapping = new Dictionary<Foo,FooManager>();
}
class-FooBase
{
受保护的静态只读字典_managerMapping=new Dictionary();
}
然后,Foo和FooManager将FooBase作为基类,可以在不对外公开映射的情况下更新它们的映射。然后您可以确定没有人会从外部更改此集合
然后在Foo中有一个属性
Manager
,该属性将返回与其关联的管理器,类似地,Manager
中的一个Foos属性将提供所有Foo。一个选项是为Foo使用私有嵌套类,该类实现公共接口:
public interface IFoo
{
// Foo's interface
}
public sealed class FooManager
{
private readonly List<Foo> _foos = new List<Foo>();
public IFoo CreateFoo()
{
var foo = new Foo(this);
_foos.Add(foo);
return foo;
}
private class Foo : IFoo
{
private readonly FooManager _manager;
public Foo(FooManager manager)
{
_manager = manager;
}
}
}
公共接口IFoo
{
//Foo的接口
}
公共密封类管理器
{
私有只读列表_foos=new List();
公共ifoocreatefoo()
{
var foo=新foo(本);
_添加(foo);
返回foo;
}
私有类Foo:IFoo
{
私有只读FooManager\u manager;
公共食品(食品经理)
{
_经理=经理;
}
}
}
由于Foo类是一个私有嵌套类,因此不能在FooManager外部创建它,因此FooManager的
CreateFoo()
方法确保所有内容保持同步。在本例中,唯一可以使关系不同步的是Foo和管理器本身。在管理器上调用CreateFoo()以创建“托管foo”。其他人可以创建一个Foo,但如果没有经理的“同意”,他们无法让经理管理它
公共类Foo
{
私人餐饮部经理;
公共无效集合管理器(FooManager)
{
if(管理者、管理者(本))
{
经理=经理;
}
其他的
{
抛出新ArgumentException(“使用Manager.CreateFoo()创建托管Foo”);
}
}
}
公共类FoodManager
{
私有列表m_foos=新列表();
public Foo CreateFoo()
{
Foo-Foo=新的Foo();
m_foos.Add(foo);
foo.SetManager(本);
返回foo;
}
公共图书馆经理办公室(Foo-Foo)
{
返回m_foos.Contains(foo);
}
}
您可以在不同类型的名称空间中创建类,让我们称之为“模块”(不要被class关键字愚弄,这不是一个:
公共静态部分类模块{
//在此“模块”外不可见
专用接口IFooSink{
无效添加(Foo-Foo);
}
公开课Foo{
私人餐饮部经理;
公共食品(食品经理){
((IFooSink)经理)。添加(此);
经理=经理;
}
}
公共类FooManager:IFooSink{
私有列表m_foos=新列表();
void IFooSink.Add(Foo-Foo){
m_foos.Add(foo);
}
}
}
由于“module”是一个分部类,因此您仍然可以在同一编译单元的其他文件中在其内部创建其他成员。我正在考虑使用反射
对于失败的设计(在CLR中缺少朋友),没有好的解决方案。这样的解决方案怎么样:
public class FriendClass
{
public void DoSomethingInMain()
{
MainClass.FriendOnly(this);
}
}
public class MainClass
{
public static void FriendOnly(object Caller)
{
if (!(Caller is FriendClass) /* Throw exception or return */;
// Code
}
}
public class NonFriendClass
{
public void DoSomething()
{
MainClass.FriendOnly(new FriendClass());
}
}
当然,这不会阻止用户执行以下操作:
public class FriendClass
{
public void DoSomethingInMain()
{
MainClass.FriendOnly(this);
}
}
public class MainClass
{
public static void FriendOnly(object Caller)
{
if (!(Caller is FriendClass) /* Throw exception or return */;
// Code
}
}
public class NonFriendClass
{
public void DoSomething()
{
MainClass.FriendOnly(new FriendClass());
}
}
我想有办法解决这个问题,但我的想法开始变得非常过分。总是有内部的可视属性,但这听起来像是一种攻击。把东西隐藏在界面后面怎么样?如果用户不让m_foos和m_manager失去同步,这样的界面会是什么样子?Foo manager能变成Foo的工厂吗?那么管理者就知道它所创建的所有Foo了。@Godeke:但是FooManager如何在不公开访问的情况下更改Foo的m_manager?为什么分离到更多的程序集是不可接受的?即使程序集中还有其他类,它们也应该是敌人的朋友和敌人(或者一些人称之为敌人的其他人)