2016-03-29 11 views
0

Wenn ich die folgende Wrapper-Klasse habe:Umgang mit generischen Eigenschaften durch Reflexion

public class Wrapper<T> 
{ 
    public T Data { get; set; } 
    public string[] Metadata { get;set; 
} 

und eine andere Klasse setzt dann diesen Wert ohne Generika:

public class SomeOtherClass 
{ 
    public object WrappedData { get;set }; 
} 

, wie kann ich an den ursprünglichen ungeöffneten Daten erhalten ?

kann ich es testen, wie mit etwas:

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>)) 
{ 
    dynamic originalValue = someOtherClass.WrappedData; 
} 

aber ich kann nicht, dann rufen Sie die .Data Eigenschaft auf originalValue, eine RuntimeBinderException bekommen.


aktualisieren

Ein wenig mehr Kontext helfen könnte. Ich arbeite an einem WebAPI, in dem ich HATEOAS implementieren möchte. Daher enthält meine Wrapperklasse die Daten, die zurückgegeben werden, plus Metadaten, und ich schreibe einen Aktionsfilter, der die Daten auspackt, sie im Antworttext zurückgibt und die Metadaten in Antwortheaders einfügt. Der Aktionsfilter wird zur Zeit wie folgt umgesetzt:

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
{ 
    if (actionExecutedContext.Request.Method == HttpMethod.Get) 
    { 
     var objectContent = actionExecutedContext.Response.Content as ObjectContent; 
     if (objectContent != null) 
     { 
     var type = objectContent.ObjectType; 
     var formatter = actionExecutedContext 
      .ActionContext 
      .ControllerContext 
      .Configuration 
      .Formatters 
      .First(f => f.SupportedMediaTypes 
       .Contains(new MediaTypeHeaderValue(actionExecutedContext 
        .Response 
        .Content 
        .Headers 
        .ContentType 
        .MediaType))); 

      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>)) 
      { 
       dynamic value = objectContent.Value; 
       actionExecutedContext.Response.Content = new ObjectContent(value.Data.GetType(), value.Data, formatter); 
      } 
     } 
    } 

    base.OnActionExecuted(actionExecutedContext); 
} 

Offensichtlich nicht alle meine API-Endpunkte zur Zeit ihre Daten wickeln, so dass, wenn die Antwort nicht eine Wrapper<T> Instanz zurückkehrt, möchte ich ohne Änderung der Antwort der Aktion Filter verlassen. Wenn dies der Fall ist, dann ziehe den Wert .Data heraus und schreibe den Antworttext damit neu.

+0

Was bedeutet 'enthalten WrapperData'?Wenn es nur den Wert von "Wrapper .Data" enthält, ist es klar. Wenn es den gesamten Wrapper enthält, sollten wir auf der Initialisierungsseite nach einem Problem suchen. –

+0

Was enthält 'Typ' Variable? –

Antwort

1

Es ist nicht klar von dem entsandten Code was objectContent.ObjectType ist, so würde ich den Code ändern, den tatsächlichen Wert zu überprüfen:

object value = objectContent.Value; 
if (value != null && value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(Wrapper<>)) 
{ 
    object data = ((dynamic)value).Data; 
    actionExecutedContext.Response.Content = new ObjectContent(data.GetType(), data, formatter); 
} 

Aber Sie können Reflexion und dynamische Anrufe vermeiden und Ihr Leben viel einfacher, wenn Sie Sichern Sie Ihre generische Klasse mit einer nicht generischen Schnittstelle. Zum Beispiel

public interface IWrapper 
{ 
    object Data { get; } 
    string[] Metadata { get; } 
} 

public class Wrapper<T> : IWrapper 
{ 
    public T Data { get; set; } 
    object IWrapper.Data { get { return Data; } } 
    public string[] Metadata { get; set; } 
} 

Dann können Sie einfach tun

var wrapper = objectContent.Value as IWrapper; 
if (wrapper != null) 
{ 
    actionExecutedContext.Response.Content = new ObjectContent(wrapper.Data.GetType(), wrapper.Data, formatter); 
} 
+0

Einfach ist das Beste :-) –

0

Wäre es hilfreich, wenn Sie den Typ Ihrem Wrapper hinzugefügt haben?

public class Wrapper<T> 
{ 
    public Type MyType{get;set;} 
    public T Data { get; set; } 
    public string[] Metadata { get;set;} 

    public Wrapper(T data){ 
     MyType = data.GetType(); 
     Data = data; 
    } 
} 
+0

Wie bekomme ich die MyType-Eigenschaft obwohl? Es ist genauso schwer zugänglich wie die Data-Eigenschaft. Wie kann ich meine Instanz von SomeOtherClass.WrappedData zu Wrapper instanziieren oder umwandeln? –

+0

Ja, das ist eine gute Frage. Entschuldigung, ich habe deinen ursprünglichen Post ein wenig falsch gelesen. Wäre es sinnvoll zu fragen, warum du diesen Trick eigentlich machen musst? Fühlt sich ein bisschen merkwürdig an mit Boxing-Werten in diesen Tagen von SOLID Design - ich bin neugierig, und Sie haben wahrscheinlich einen ganz guten Grund dafür :) –

+0

Ich habe meine Frage mit etwas mehr Kontext aktualisiert. –

0

Unklare genau das, was Sie zu tun versuchen:

object obj = new Wrapper<SomeOtherClass> { Data = new SomeOtherClass { WrappedData = "Hello" } }; 
Type type = obj.GetType(); 

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>)) 
{ 
    dynamic data = ((dynamic)obj).Data; 
    dynamic wrappedData = data.WrappedData; 
} 

Beachten Sie, dass keine Garantie gibt, dass es eine WrappedData Eigenschaft innerhalb der Data Eigenschaft ist: WrappedData ist eine Eigenschaft von SomeOtherClass, sondern zum Beispiel obj könnte sein:

object obj = new Wrapper<string> { Data = "Hello" }; 
1

Der folgende Code funktioniert:

So, es ist nicht klar, was Ihr Problem ist!

Verwandte Themen