Приведение родителя к своему родовому ребенку - PullRequest
0 голосов
/ 29 января 2019

У меня есть следующие настройки:

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 голосов
/ 29 января 2019

Один вариант для рассмотрения:

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

Это аналогичный подход к подходам, основанным на отражении, но немного более краткий.

0 голосов
/ 29 января 2019

Вы можете сделать это с помощью отражения без каких-либо модификаций классов:

public void SetValue(object val)
{
    Source.GetType().GetProperty("Value").SetValue(Source, value);
}
0 голосов
/ 29 января 2019

Небольшой вариант ответа, уже предоставленный Славой Утесиновым

   // 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<>");
   }
0 голосов
/ 29 января 2019

Вы должны использовать шаблон посетителя:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...