我需要能够调用一个方法并传入一个未知类型的对象
但然后调用正确的重载。我还需要一个接受的默认实现
object
作为参数类型。我所看到的是默认的重载是唯一被使用过的。
以下是我要做的事情的要点:
class Formatter
{
private object Value;
public Formatter(object val){
Value = val;
}
public override string ToString()
{
return Format(Value);
}
private string Format(object value)
{
return value.ToString();
}
private string Format(DateTime value)
{
return value.ToString("yyyyMMdd");
}
}
好的,到目前为止一切顺利。现在我希望能够做到这一点:
public static class FancyStringBuilder()
{
public static string BuildTheString()
{
var stringFormatter = new Formatter("hello world");
var dateFormatter = new Formatter(DateTime.Now);
return String.Format("{0} {1}", stringFormatter, dateFormatter);
}
}
FancyStringBuilder.BuildTheString()
的结果是"hello world 2012-12-21 00:00:00.000"
,当我预期"hello world 20121221"
问题是没有调用接受DateTime
的重载,而是默认为接受object
的重载。 如何在不诉诸凌乱的switch语句的情况下调用正确的方法?
答案 0 :(得分:1)
我认为这是因为类构造函数将object
作为参数,然后将该对象分配给变量Value
,这也是object
。由于Value
的类型为object
试试这个
public override string ToString()
{
if(Value is DateTime)
return Format(Convert.ToDateTime(Value)); //this should call the right method
return Format(Value); //works for other non-custom-format types e.g. String
}
答案 1 :(得分:1)
在Formatter.ToString()
中,覆盖Formatter.Format(object)
始终被调用。这是因为重载解析在编译时发生,而不是在运行时发生。在编译时,Value
唯一知道的是它是一个对象。
如果你真的想区分传入的类型,你需要在Formatter
的构造函数中这样做。在这种情况下,您可以立即调用ToString()
而不是挂在对象上,而只是存储格式化的结果:
class Formatter
{
string formattedValue;
public Formatter(object value)
{
formattedValue = value.ToString();
}
public Formatter(DateTime value)
{
formattedValue = value.ToString("yyyyMMdd");
}
public string ToString()
{
return formattedValue;
}
}
请注意,这确实假设您的对象在创建Formatter
对象和调用时间Formatter.ToString()
之间没有变化,或者至少可以拍摄快照<{1}}创建时的字符串表示形式。
这也假定您在编译时知道传入的类型。如果您想要一个真正的仅限运行时的解决方案,则必须使用“是”运算符或Formatter
比较。
如果您的目标只是根据传入类型提供自定义ToString()格式,我可能会使用从类型映射到格式字符串的列表来执行此操作:
typeof()
然后,调用代码看起来像:
static class Formatter
{
private static List<Tuple<Type, string>> Formats;
static Formatter()
{
Formats = new List<Tuple<Type, string>>();
// Add formats from most-specific to least-specific type.
// The format string from the first type found that matches
// the incoming object (see Format()) will be used.
AddMapping(typeof(DateTime), "yyyyMMdd");
// AddMapping(typeof(...), "...");
}
private static void AddMapping(Type type, string format)
{
Formats.Add(new Tuple<Type, string>(type, format));
}
public static string Format(object value)
{
foreach (var t in Formats)
{
// If we find a type that 'value' can be assigned to
// (either the same type, a base type, or an interface),
// consider it a match, and use the format string.
if (t.Item1.IsAssignableFrom(value.GetType()))
{
return string.Format(t.Item2, value);
}
}
// If we didn't find anything, use the default ToString()...
return value.ToString();
}
}