In Scala können Sie Mustervergleiche verwenden, um ein Ergebnis in Abhängigkeit vom Typ der Eingabe zu erzeugen. Zum Beispiel:
val title = content match {
case blogPost: BlogPost => blogPost.blog.title + ": " + blogPost.title
case blog: Blog => blog.title
}
In C# möchte ich idealerweise in der Lage sein, zu schreiben:
var title = Visit(content,
(BlogPost blogPost) => blogPost.Blog.Title + ": " + blogPost.Title,
(Blog blog) => blog.Title
);
Ist das möglich? Wenn ich versucht habe, es als eine einzelne Methode zu schreiben, weiß ich nicht, wie ich die Generika angeben kann. Die folgende Implementierung scheint richtig zu sein, abgesehen davon, dass die Typüberprüfung Funktionen zulässt, die Subtypen von T akzeptieren:
public TResult Visit<T, TResult>(T value, params Func<T, TResult>[] visitors)
{
foreach (var visitor in visitors)
{
if (visitor.Method.GetGenericArguments()[0].IsAssignableFrom(value.GetType()))
{
return visitor(value);
}
}
throw new ApplicationException("No match");
}
Am nächsten komme ich, wenn ich die Funktionen einzeln zu einem Objekt hinzufüge und dann visit für einen Wert aufrufe:
public class Visitor<T, TResult>
{
private class Result
{
public bool HasResult;
public TResult ResultValue;
}
private readonly IList<Func<T, Result>> m_Visitors = new List<Func<T, Result>>();
public TResult Visit(T value)
{
foreach (var visitor in m_Visitors)
{
var result = visitor(value);
if (result.HasResult)
{
return result.ResultValue;
}
}
throw new ApplicationException("No match");
}
public Visitor<T, TResult> Add<TIn>(Func<TIn, TResult> visitor) where TIn : T
{
m_Visitors.Add(value =>
{
if (value is TIn)
{
return new Result { HasResult = true, ResultValue = visitor((TIn)value) };
}
return new Result { HasResult = false };
});
return this;
}
}
Dies kann folgendermaßen verwendet werden:
var title = new Visitor<IContent, string>()
.Add((BlogPost blogPost) => blogPost.Blog.Title + ": " + blogPost.Title)
.Add((Blog blog) => blog.Title)
.Visit(content);
Irgendeine Idee, wie man dies mit einem einzigen Methodenaufruf tun?