将父母抛给其普通子女

时间:2019-01-29 12:09:16

标签: c# unity3d

我有以下设置:

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;
        }
    }
}

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

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

((Child) Source).Value = (val.GetType()) val;

,而不是开关。这有可能吗?

4 个答案:

答案 0 :(得分:5)

您应该使用访客模式:

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

这意味着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); }
   ...
}

然后定义BaseClassVisitor接口:

public interface BaseClassVisitor {
    void Visit(IntChild intChild);
    void Visit(...); // all the other possible types
    ...
}

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

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

以下是一个完整的示例,可以使事情更清楚:

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);
        }
    }
}

这将输出:

intChild.Value    = 12345
floatChild.Value  = 1,2345
stringChild.Value = Hello World

答案 1 :(得分:1)

您可以通过反射来完成它,而无需修改类:

public void SetValue(object val)
{
    Source.GetType().GetProperty("Value").SetValue(Source, value);
}

答案 2 :(得分:0)

Slava Utesinov已经提供了答案的小变化

   // Only set value if implementation of Child<>. 
   // If any other derived class of BaseClass with value field, then dont set 
   if(source.GetType().BaseType != null 
      && source.GetType().BaseType.IsGenericType 
      && source.GetType().BaseType.GetGenericTypeDefinition() == typeof(Child<>)) 
   {
       Console.WriteLine("Is implementation of Child<>");
       source.GetType().GetField("Value").SetValue(source, val);

   } 
   else 
   {
       Console.WriteLine("Not implementation of Child<>");
   }

答案 3 :(得分:0)

要考虑的一个选项:

public void SetValue(object val)
{
    dynamic dynamicSource = Source;
    dynamicSource.Value = val;
}

与基于反射的方法类似,但更加简洁。