如何做一个肤浅的参考

时间:2014-07-07 15:41:05

标签: c#

我想知道如何强制一个变量始终指向另一个变量指向的内容。

考虑以下计划:

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表示将被操作的存储库。我试图松散地耦合事物,以便它们易于调试。

4 个答案:

答案 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");
    }

}    

如果这导致良好的整体设计是一个完全不同的问题!