Ich versuche, eine Menge meines Codes zu bereinigen, der sich auf das Erstellen von Web-Service-Anforderungen bezieht und zwischen Ansichtsmodellen und Datenübertragungsobjekten hin und her mappt. Im Moment habe ich die folgende Einstellung in meinem Code:Entfernen überflüssige generische Argumente von einer Methode
public class Request1 : IRequest<Type1>
{
public Type1 Data { get; set; }
}
public interface IRequest<T>
{
T Data { get; set; }
}
public class Type1
{
string Account {get; set; }
...
}
public static class Mapper
{
public static TOut CreateRequest<TOut, TIn>(TIn data) where TIn : IRequest<TIn>, new()
{
var request = new TOut();
request.Data = data;
return request;
}
}
Die oben ermöglicht es mir, Generika zu verwenden, um die Request1
-Objekt zu erstellen, indem man wirklich einfach in den Daten.
var model = new ViewModel();
var data = Mapper.mapFromViewModel(model);
var request = Mapper.CreateRequest<Request1,Type1>(data);
Dies ist GREAT meiner Meinung nach, aber es hat einen Schönheitsfehler.
Die Daten, die ich übergebe, müssen vom Typ dto sein (Type1
) in der Anfrage. Was ich tun möchte ist, die Daten in ihrer rohen Form zu übergeben, also würde ich in der Benutzeroberfläche die Daten des Ansichtsmodells und die Art der gewünschten Anfrage übergeben. Die Methode würde die Zuordnung zwischen dem Ansichtsmodell und dem Dto-Typ ausarbeiten und dann die Anfrage für mich erstellen.
Also, wenn ich ein bisschen AutoMapper
verwenden, um die Zuordnung zwischen der View-Modell und dem dto Typ verarbeiten kann ich diese:
public TOut CreateRequest2<TOut, TDto, TModelIn>(TModelIn data)
where TOut : IRequest<TDto>, new()
{
var request = new TOut();
request.Data = Map<TModelIn, TDto>(data);
return request;
}
Was ich wie diese verwenden:
var model = new ViewModel();
var request = Mapper.CreateRequest2<Request1,Type1,ViewModel>(model);
Das ist fast da ... aber hier bin ich an der Wand meines Wissens.
Ich möchte in der Lage sein, die TDto
Anforderung von dem Anruf zu schneiden, so muss der Anrufer nur über die Request
und die ViewModel
Typen kennen.
Etwas wie:
public TOut CreateRequest3<TOut, TModelIn>(TModelIn data)
{
// Cast? the TOut to IRequest<>
// Extract the TDto type from the IRequest<> object and
// pass the TDto type into the method I created earlier.
return CreateRequest2<TOut,TDto,TModelIn>(data);
}
Wer weiß, ob dies erreicht werden kann?
Die Oberseite von diesem ist, um die Notwendigkeit für meinen UI-Code zu entfernen, um zu wissen, welche DTO für eine Nachricht erforderlich ist, und lassen Sie das von Autoadapter basierend auf dem Ansichtsmodell behandelt werden, das es angegeben wird.
UPDATE: So folgende Vorschläge von @EpicSam Ich habe jetzt die folgende, die funktioniert:
public TOut CreateRequest3<TOut, TModelIn>(TModelIn data) where TOut : class, new()
{
var interfaces = typeof(TOut).GetInterfaces().FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IRequest<>));
var dtoType = interfaces?.GenericTypeArguments.FirstOrDefault();
var result = typeof(Mapper)
.GetMethod(nameof(Mapper.CreateRequest))
.MakeGenericMethod(typeof(TOut), dtoType, typeof(TModelIn))
.Invoke(this, new object[ ] {data});
return result as TOut;
}
Das ist hässlich, aber es ist in Ordnung, wie der immer nur einmal geschrieben. Aber was muss ich sonst über diesen Code wissen? Wie es Reflexion verwendet, ist es dabei, meine Leistung hämmern, oder sollte ich auch nur darüber keine Sorgen ....
UPDATE 2: Der Reflexions Code ist etwa 3x langsamer als die Original-Code habe ich geschrieben. Obwohl ich mich entscheiden könnte, meinen Code schöner und sauberer zu machen, werde ich mich dafür entscheiden, ihn so zu belassen, wie er ist, und effizienter zu arbeiten.
Vielleicht benutzerdefinierte Attribute (https://msdn.microsoft.com/en-us/library/84c42s56.aspx) um ein Mapping zu definieren ist der Schlüssel? – ViRuSTriNiTy
Nicht sicher, warum das helfen würde. Ich weiß, was der 'TDto'-Typ ist, wie es in der 'IRequest' auf der Anfrage-Klasse ist. Es ist nur so, wie ich es rauskriege. –
Nick
Den Typ zu erhalten ist einfach: 'typeof (TOut) .GenericTypeArguments [0]' (Sie möchten wahrscheinlich eine Basis-IRequest-Schnittstelle erstellen, so dass Sie zumindest 'TOut' darauf beschränken können). Aber Sie können es nicht statisch übergeben (Sie können die Methode durch Reflexion aufrufen, aber das ist ziemlich hässlich). Ich denke, dass Automapper einige Überladungen hat, um den Typ zur Laufzeit zu übergeben. –