将父级转换为其通用子级

MGG*_*GGD 0 c# unity-game-engine

我有以下设置:

public class Child<T>: BaseClass
{
    public T Value;
}

public class IntChild: Child<int> { }

public class BoolChild: Child<bool> { }

public class FloatChild: Child<float> { }

public class MyProgram
{
    public BaseClass Source;

    public void SetValue(object val)
    {
        // I want to do something like the following
        // ((Child) Source).Value = (val.GetType()) val;

        // Instead, I have to do it like this
        string temp = val.ToString();
        switch (Source.GetType())  
        {
            case "IntChild":
                ((IntChild) Source).Value = int.Parse(val.ToString());
                break;
            case "BoolChild":
                ((BoolChild) Source).Value = bool.Parse(val.ToString());
                break;
            case "FloatChild":
                ((FloatChild) Source).Value = float.Parse(val.ToString());
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我无法修改BaseClass(我只能覆盖ToString()).

如何用更简单的代码替换开关?我想做类似以下的事情

((Child) Source).Value = (val.GetType()) val;
Run Code Online (Sandbox Code Playgroud)

而不是开关.这甚至可能吗?

fja*_*don 5

你应该使用访客模式:

public abstract class BaseClassWithVisitor : BaseClass {
  void AcceptVisitor(BaseClassVisitor visitor);
}
Run Code Online (Sandbox Code Playgroud)

这意味着Child<T>变得抽象.

使所有Child<T>子类实现BaseClassWithVisitor.AcceptVisitor()方法,因此它们不是抽象的:

public class IntChild : Child<int> {
   ...
   /// This method should be implemented in all Child<T> descendant classes
   public override void AcceptVisitor(BaseClassVisitor visitor) { visitor.Visit(this); }
   ...
}
Run Code Online (Sandbox Code Playgroud)

然后定义BaseClassVisitor接口:

public interface BaseClassVisitor {
    void Visit(IntChild intChild);
    void Visit(...); // all the other possible types
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后最终创建一个BaseClassVisitor将执行您想要的操作的实现:

public class SetValueVisitor : BaseClassVisitor {
    void Visit(IntChild intChild) { intChild.Value = 1; }
    void Visit(BoolChild boolChild) { boolChild.Value = false; }
    ...
}
Run Code Online (Sandbox Code Playgroud)

这是一个让事情更清晰的完整示例:

using System;
using System.Globalization;

namespace Visitor
{
    class BaseClass
    {
    }

    abstract class BaseClassWithVisitor : BaseClass
    {
        public abstract void AcceptVisitor(Visitor visitor);
    }

    abstract class Child<T> : BaseClassWithVisitor
    {
        public T Value;
    }

    class IntChild : Child<int>
    {
        public override void AcceptVisitor(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }
    class FloatChild : Child<float>
    {
        public override void AcceptVisitor(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }
    class StringChild : Child<string>
    {
        public override void AcceptVisitor(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Visitor
    {
        public object Value;

        public void Visit(IntChild intChild)
        {
            intChild.Value = int.Parse(Value.ToString());
        }
        public void Visit(FloatChild floatChild)
        {
            floatChild.Value = float.Parse(Value.ToString(), CultureInfo.InvariantCulture);
        }
        public void Visit(StringChild stringChild)
        {
            stringChild.Value = Value.ToString();
        }
    }


    class Program
    {
        static void Main(string[] args)
        {

            var visitor = new Visitor { Value = "12345" };
            var intChild = new IntChild();
            intChild.AcceptVisitor(visitor);

            visitor = new Visitor { Value = "1.2345" };
            var floatChild = new FloatChild();
            floatChild.AcceptVisitor(visitor);

            visitor = new Visitor { Value = "Hello World" };
            var stringChild = new StringChild();
            stringChild.AcceptVisitor(visitor);

            Console.WriteLine("intChild.Value    = {0}", intChild.Value);
            Console.WriteLine("floatChild.Value  = {0}", floatChild.Value);
            Console.WriteLine("stringChild.Value = {0}", stringChild.Value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将输出:

intChild.Value    = 12345
floatChild.Value  = 1,2345
stringChild.Value = Hello World
Run Code Online (Sandbox Code Playgroud)