我有以下设置:
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;
,而不是开关。这有可能吗?
答案 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;
}
与基于反射的方法类似,但更加简洁。