2013-04-04 13 views
5

Oto urywek klasy używać do metod rozszerzenie badań typu:Wywołanie ogólne metodę rozszerzenia bez określania jak wiele rodzajów

class Something 
{ 
    [StringLength(100, MinimumLength = 1, ErrorMessage = "Must have between 1 and 100 characters")] 
    public string SomePublicString { get; set; } 
} 

Mam następującą metodę rozszerzenia:

public static class TypeExtensions 
{ 
    public static TAttributeType GetCustomAttribute<T, TAttributeType, TProperty>(this T value, Expression<Func<T, TProperty>> propertyLambda, bool inherit = false) 
    { 
    var type = typeof(T); 
    var member = (MemberExpression)propertyLambda.Body; 
    var propertyInfo = (PropertyInfo)member.Member; 
    var customAttributes = propertyInfo.GetCustomAttributes(typeof(TAttributeType), inherit); 

    return customAttributes.OfType<TAttributeType>().FirstOrDefault(); 
    } 
} 

Użycie w teście jednostkowym:

1: var something = new Something(); 
2: var actual = something.GetCustomAttribute<Something, StringLengthAttribute, string>(x => x.SomePublicString); 

3: actual.MinimumLength.Should().Be(1); 
4: actual.MaximumLength.Should().Be(100); 
5: actual.ErrorMessage.Should().Be("Must have between 1 and 100 characters"); 

Ta funkcja zwraca test zaliczający (przy użyciu FluentAssertions).

Jednak chciałbym, aby uzyskać połączenie metoda GetCustomAttribute() w wierszu 2 w dół do następujących:

var actual = something.GetCustomAttribute<StringLengthAttribute>(x => x.SomePublicString); 

Czy to możliwe? Czy czegoś brakuje? Może mam awarię kofeiny. :(

Odpowiedz

7

Nie, to albo trzeba określić wszystkie argumenty typu, lub żaden z nich. Nie ma "częściowego" wnioskowania typu.

Jedną z metod, z których można czasem uciec, jest posiadanie jednej ogólnej metody z pojedynczym argumentem typu, który zwraca instancję klasy ogólnej, a następnie wykorzystanie jej do wykonania pozostałych czynności - lub odwrotnie . W tym przypadku może to być rzeczywiście najlepiej oddzielić atrybut ściągam z resztą i tak:

something.GetPropertyAttributes(x => x.SomePublicString) 
     .FirstAttribute<StringLengthAttribute>(); 

Oto pierwsze wywołanie metody wywodzi T i TProperty - i po prostu zwraca IEnumerable<Attribute> i FirstAttribute byłoby po prostu zrobić OfType/FirstOrDefault połączenia. (Możesz nawet zdecydować, że nie potrzebujesz FirstAttribute, ponieważ możesz łatwo zadzwonić pod numer OfType i FirstOrDefault).

+1

Huzzah dla zasady pojedynczej odpowiedzialności. – StriplingWarrior

+0

Dzięki. Pierwotnie miałem coś w rodzaju próbki kodu, wyodrębniając odbicie 'PropertyInfo', niestandardowe odbicia atrybutów, i wreszcie, typ jakiego potrzebowałem, ale liczyłem na coś ... szczuplejszego. :-) –

+0

@Dan, często słyszałem, że skarga dotyczyła tego rozwiązania i nigdy naprawdę nie rozumiał skąd pochodzi.Wydaje się być dla mnie bardzo szczupła (dla konsumentów). –

3

Nie jest możliwe, aby wyprowadzić niektóre, ale nie wszystkie, z argumentów typu, nie

można:.

  1. określić wszystkie z ogólnych argumentów

  2. .
  3. Upewnij się, że można wywnioskować wszystkie ogólne argumenty. (Nie zawsze jest to możliwe lub kompromisy potrzebne do uwzględnienia wnioskowania mogą nie być pożądane.)

  4. Przerwij metodę na wiele metod, tak aby jedna metoda zawierała ogólne argumenty, a druga nie.

+0

Dzięki. Moja metoda rozszerzenia nie zawiera jednak żadnych typów, ponieważ muszę określić wszystkie używane typy. Czy jest to "czyste", ponieważ mogę uzyskać wywołanie metody? –

+1

@DanAtkinson Bez zmiany podpisu metody, tak. Jak już powiedziałem, wnioskowanie to wszystko albo nic. – Servy

Powiązane problemy