我想知道如何强制一个变量始终指向另一个变量指向的内容。
考虑以下计划:
using System;
public class Program
{
public static void Main()
{
Person p = new Person{Name = "Aelphaeis", Age = -1};
p.introBehavior.Introduce();
}
class Person
{
public String Name { get;set; }
public Int32 Age { get;set; }
public IIntroductionBehavior introBehavior{get;set;}
public Person(){
Name = "over";
Age = 9000;
introBehavior = new IntroductionBehavior(Name, Age);
}
}
class IntroductionBehavior : IIntroductionBehavior
{
String Name;
Int32 Age;
public IntroductionBehavior(string name, int age){
Age = age;
Name = name;
}
public void Introduce(){
Console.WriteLine("I'm " + Name + " and I am " + Age + " years old");
}
}
interface IIntroductionBehavior
{
void Introduce();
}
}
如果您运行此程序,您将获得
我结束了,我已经9000岁了
对于IntroductionBehavior内部的Name和Age,所期望的行为是指向Person内部属性的值也指向的内容。它应该打印:
我是Aelphaeis,我是-1岁
如果不可能,我可以实现哪种类型的重新设计,以确保IntroductionBehavior始终打印Person的值而不使IntroductionBehavior知道Person?
编辑:很多人似乎对为什么我不想让IntroductionBehavior意识到人而感到困惑。
简介实际上是为了对存储库执行操作。变量name和age表示将被操作的存储库。我试图松散地耦合事物,以便它们易于调试。
答案 0 :(得分:3)
将IntroductionBehavior
引用给人:
class IntroductionBehavior : IIntroductionBehavior
{
private Person person;
public IntroductionBehavior(Person person){
this.person = person;
}
public void Introduce(){
Console.WriteLine("I'm {0} and I am {1} years old",
person.Name, person.Age); // NOTE: use string format
}
}
class Person
{
public String Name { get; set; }
public Int32 Age { get; set; }
public IIntroductionBehavior introBehavior { get; set; }
public Person(){
Name = "over";
Age = 9000;
introBehavior = new IntroductionBehavior(this);
}
}
因此IntroductionBehavior
会在您要求它介绍时获得姓名和年龄值或人物。
另一个选择是在属性getter中创建IntroductionBehavior
实例,而不是在构造函数中创建它:
public IIntroductionBehavior introBehavior
{
get { return new IntroductionBehavior(Name, Age); }
}
因此,IntroductionBehavior
将在您获得人的姓名和年龄值时捕获人的姓名和年龄值,而不是创建人的时间。注意:如果您在获取introBehavior
和介绍之前更新此人的姓名或年龄,那么您将看到旧数据。
当然,使用IntroductionBehavior
类是有争议的。
答案 1 :(得分:3)
通常,您在C#中执行的操作是将对象的父级传递给其构造函数。在这种情况下,IntroductionBehavior
会存储父Person
。
例如:
class IntroductionBehavior : ...
{
public Person Parent {get; private set;}
public IntroductionBehavior(Person parent)
{
Parent = parent;
}
...
}
然后您可以使用Parent.Age
来获得年龄。
答案 2 :(得分:2)
三个想法:
1)为什么你可以做一个单独的课程IntroductionBehavior
:
class Person : IIntroductionBehavior
{
public String Name { get;set; }
public Int32 Age { get;set; }
public Person(){
Name = "over";
Age = 9000;
}
public void Introduce()
{
Console.WriteLine("I'm " + Name + " and I am " + Age + " years old");
}
}
2)您可以实现属性getters / setters来修改行为
public String Name
{
get { return introBehavior.Name; }
set { introBehavior.Name = value; }
}
public Int32 Age
{
get { return introBehavior.Age; }
set { introBehavior.Age = value; }
}
3)您也可以封装整个行为
这可以与2)结合使用,因此您可以这样做,而不是将属性introductionBehavior
定义为可设置:
private IntroductionBehavior introBehavior;
public Person()
{
introBehavior = new IntroductionBehavior() { Name = "Test", Age = 123 };
}
public IIntroductionBehavior introductionBehavior
{
get { return introBehavior; }
}
public String Name
{
get { return introBehavior.Name; }
set { introBehavior.Name = value; }
}
public Int32 Age
{
get { return introBehavior.Age; }
set { introBehavior.Age = value; }
}
结合2)和3)仅在行为中存储姓名和年龄而不是重复信息(Person
中的2个属性,introductionBehavior
中的两个属性)。
我觉得introductionBehavior
可以从Person
类之外设置,这是值得怀疑的。这就是为什么我认为3)是一个好方法。你在评论中说,所有这些都是关于独立于Person
类的界面的自动测试。在我看来,2)和3)的组合使您可以通过测试Person
来完成部分测试IntroductionBehavior
的额外好处。
答案 3 :(得分:1)
您可以使用以下帮助程序模板SharedValue<T>
来创建对值的引用(即添加另一级别的间接)。
这允许您共享值。如果要访问&#34; real&#34;您必须将.Value
添加到变量中。值,否则你只需得到&#34;指针&#34;。
这与shared_ptr
中的C++
(或任何其他类似指针的构造)相当。
class SharedValue<T>
{
T Value; // stores a single value
}
您的代码将如下所示:
class Person
{
private readonly SharedValue<string> name = new SharedValue<string>();
private readonly SharedValue<Int32> age = new SharedValue<Int32>();
public String Name { get {return name.Value;} set {name.Value = value;} }
public Int32 Age { get {return age.Value;} set {age.Value = value;} }
public IIntroductionBehavior introBehavior{get;set;}
public Person(){
Name = "over";
Age = 9000;
introBehavior = new IntroductionBehavior(name, age); // note that we pass the SharedValues
}
}
class IntroductionBehavior : IIntroductionBehavior
{
SharedValue<String> Name;
SharedValue<Int32> Age;
public IntroductionBehavior(SharedValue<string> name, SharedValue<int> age){
Age = age;
Name = name;
}
public void Introduce(){
Console.WriteLine("I'm " + Name.Value + " and I am " + Age.Value + " years old");
}
}
如果这导致良好的整体设计是一个完全不同的问题!