2015-02-11 3 views
0

Я пытаюсь десериализовать выход xml из REST API. После десериализации я должен проверить, имеет ли ответ действительные данные.typeof (T) для внутреннего списка

public class Response 
{ 
public UserWrapper Users { get; set; } 
public MovieWrapper Movies { get; set; } 
} 

public class UserWrapper 
{ 
    [XmlElement("User")] 
    public User[] UserList { get; set; } 
} 

public class MovieWrapper 
{ 
    [XmlElement("Movie")] 
    public Movie[] MovieList { get; set; } 
} 

public static bool isValidUserResponse(this Response response) 
{ 
return response.Users != null && response.Users.UserList != null 
} 

public static bool isValidMovieResponse(this Response response) 
{ 
return response.Movies!= null && response.Movies.MovieList != null 
} 

Структура XML-ответ

<Response> 
<Users> 
    <User>...</User> 
    <User>...</User> 
    <User>...</User> 
</Users> 
</Response> 

<Response> 
<Movies> 
    <Movie>...</Movie> 
    <Movie>...</Movie> 
    <Movie>...</Movie> 
</Movies> 
</Response> 

Как мне сделать мой isValidUserResponse() и isValidMovieResponse() в качестве одного общего метода?

+7

Не совсем понятно, о чем вы спрашиваете - мы понятия не имеем, где «MovieList» вошел бы в что-либо или что «Response» и т. Д. Пожалуйста, предоставьте больше контекста и пример того, как вы это сделаете * без * generics было бы хорошим началом ... (Я также рекомендую вам начать следовать соглашениям об именах .NET и изменить тело метода на 'return response.Users! = null && response.Users.UserList! = null; '.) –

+0

Я бы назвал ваш список' List', а не 'UserList',' MovieList' и т. Д. Это сделало бы сопоставление с использованием интерфейса. –

+0

@JonSkeet Я обновил свой вопрос. Надеюсь это поможет. Также спасибо за то, что я настаивал на соглашениях .NET. –

ответ

3

Вы не можете просто использовать дженерики для этого - по крайней мере, не легко. Вы могли написать что-то вроде:

public static void IsValidResponse<T>(this Response response, 
    Func<Response, T> firstPropertyFetcher, 
    Func<T, object> secondPropertyFetcher) where T : class 
{ 
    T property = firstPropertyFetcher(response); 
    return property != null && secondPropertyFetcher(property) != null; 
} 

и назвать его:

response.IsValidResponse(r => r.Users, u => u.UserList); 
response.IsValidResponse(r => r.Movies, u => u.MovieList); 

... но я не уверен, что чище.

Или вы могли использовать отражение, чтобы изучить все свойства в Response и найти те, с типом «мишени», и проверить тех, кто ... но это немного некрасиво.

Нужно ли проверять каждую часть ответа отдельно? Если нет, вы можете рассмотреть возможность предоставления каждому классу собственного метода IsValid.

В качестве альтернативы, я считаю, что есть некоторые общие проекты проверки подлинности с открытым исходным кодом, которые могут вам помочь, но у меня нет опыта с ними.

2
public class Response 
{ 
    public UserWrapper Users { get; set; } 
    public MovieWrapper Movies { get; set; } 

    public Response() 
    { 
     Users = new UserWrapper(); 
     Movies = new MovieWrapper(); 
    } 

    public bool IsValid<T>() where T : IList 
    { 
     var property = this.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public).First(p => p.PropertyType.Equals(typeof(T))); 
     var collection = property.GetValue(this) as IList; 
     return collection.Count > 0; 
    } 
} 

public class User 
{ 
    // ... 
} 

public class Movie 
{ 
    // ... 
} 

public class UserWrapper : List<User> 
{ 
    // ... 
} 

public class MovieWrapper : List<Movie> 
{ 
    // ... 
} 

И тогда мы получим:

static void Main(string[] args) 
     { 
      var res = new Response(); 
      res.Users.Add(new User()); 
      Console.WriteLine(res.IsValid<UserWrapper>().ToString()); // "true" 
      Console.WriteLine(res.IsValid<MovieWrapper>().ToString()); // "false" 
     } 

Итак, вот что происходит: this.GetType() дает нам Response Тип объекта, который хранит все метаданные о нем; Мы получаем все общедоступные свойства, которые принадлежат экземпляру, и мы ищем первый тип с возвращаемым типом (PropertyType), который идентичен тому, который мы ищем: T. Мы используем property, чтобы получить соответствующую коллекцию из экземпляра (property.GetValue(this)), а затем мы просто посчитаем это.

Обратите внимание, что если у вас есть два свойства одного типа - этот шаблон не будет работать.