2009-04-27 10 views
13

Ok. Mam więc kod, który odwzorowuje określone kontrolki na winForm na pewne właściwości w obiekcie, w celu wykonania pewnych czynności na elementach sterujących, gdy pewne rzeczy zdarzają się danym. Wszystko dobrze i dobrze, działa dobrze. Nie problem. Problem jest, aby dodać elementy do mapowania, wzywam funkcję, która wygląda tak:Wyodrębnianie nazw właściwości dla odbicia za pomocą IntelliSense i sprawdzanie w czasie kompilacji

this.AddMapping(this.myControl,myObject,"myObjectPropertyName"); 

Problem napotkasz jest to, że bardzo trudno jest powiedzieć, w czasie kompilacji, różnica pomiędzy powyższej linii a poniżej:

this.AddMapping(this.myControl,myObject,"myObjectPropretyName"); 

Ponieważ ostatni parametr jest ciągiem znaków, nie ma czasu kompilacji sprawdzanie czy coś w tym, że wymusi że sam ciąg faktycznie odpowiada poprawną nazwą nieruchomości na danym obiekcie. Dodatkowo, takie rzeczy jak Refactor i "Find All References" omijają ten rodzaj odniesienia, co powoduje radość, gdy zmienia się nazwa samej nieruchomości. Zastanawiam się więc, czy istnieje sposób na zmianę funkcji, tak, że to, co przekazuję, jest nadal ciągiem reprezentującym nazwę właściwości w jakiś sposób, ale z kompilacją czasu sprawdzania rzeczywistej wartości wchodzącej. Ktoś powiedział można to zrobić za pomocą Expression Trees, ale przeczytałem je i wydaje mi się, że nie widzę połączenia. Chciałbym zrobić coś takiego:

this.AddMapping(this.myControl,myObject,myObject.myObjectPropertyName); 

lub nawet

this.AddMapping(this.myControl,myObject.myObjectPropertyName); 

będzie słodka!

Wszelkie pomysły?

+0

Trwało 6 lub 7 przebiegów, zanim mogłem zauważyć różnicę w dwóch liniach kodu. – jjnguy

+0

Witajcie w moim piekle ... wyobraźcie sobie teraz, że jest zaśmiecony akronimami takimi jak CPCR, CPR, CLI, itd ... – GWLlosa

+0

Przez najdłuższy czas pragnęłem jakiegoś dodatku VS, który wypakowałby wszystkie struny w waszym sprawdzanie kodu i pisowni. Uwzględniłoby to także osłonę wielbłąda i sprawdzanie pisowni każdego słowa osobno. Ktoś musi napisać ten frajer ... – BFree

Odpowiedz

14

w 3.5, Wyrażenie jest jednym ze sposobów określania nazw członków jako kodu; mógłbyś:

public void AddMapping<TObj,TValue>(Control myControl, TObj myObject, 
     Expression<Func<TObj, TValue>> mapping) {...} 

a następnie parsować drzewo wyrażenie, aby uzyskać wartość. Trochę nieefektywne, ale nie tak źle.

Oto przykładowy kod:

public void AddMapping<TSource, TValue>(
     Control control, 
     TSource source, 
     Expression<Func<TSource, TValue>> mapping) 
    { 
     if (mapping.Body.NodeType != ExpressionType.MemberAccess) 
     { 
      throw new InvalidOperationException(); 
     } 
     MemberExpression me = (MemberExpression)mapping.Body; 
     if (me.Expression != mapping.Parameters[0]) 
     { 
      throw new InvalidOperationException(); 
     } 
     string name = me.Member.Name; 
     // TODO: do something with "control", "source" and "name", 
     // maybe also using "me.Member" 
    } 

nazywa się:

AddMapping(myControl, foo, f => f.Bar); 
1

Naprawdę nie powinieneś przekazywać literałów String jako nazwy właściwości. Zamiast tego powinieneś używać YourClass.PROPERTY_NAME_FOO.

Powinieneś zadeklarować te Struny jako stałe w twojej klasie.

public const String PROPERTY_NAME_FOO = "any string, it really doesn't matter"; 
public const String PROPERTY_NAME_BAR = "some other name, it really doesn't matter"; 

Albo, nie trzeba się martwić o Strings w ogóle, tylko nazwy własności:

public const int PROPERTY_NAME_FOO = 0; 
public const int PROPERTY_NAME_BAR = 1; //values don't matter, as long as they are unique 

To by zatrzymać ciągi, które nie odnoszą się do ważnej własności przed przedostaniem się do wywołania funkcji .

Serwis Intelisense będzie mógł wyświetlać nazwy nieruchomości z klasy jako sugestie automatycznego uzupełniania.

+0

Pomyślałem o tym, Jedyne, co mnie martwi, to to, że jest zbędny ... Teraz zachowujesz informacje o właściwościach w 2 oddzielnych miejscach (ciąg const i sama nazwa właściwości), co wydaje się być mniej niż optymalne. – GWLlosa

+0

Naprawdę nie musisz używać Stringa. Możesz po prostu zamapować je na ints lub cokolwiek innego. Jest to nazwa, która jest ważna, oraz fakt, że wartości są unikalne. – jjnguy

+0

Ale jeśli nie zamapuję ich na ciągi, w jaki sposób mogę uzyskać wartość ciągu? – GWLlosa

2

Rozważ użycie lambdy lub nawet System.Linq.Expressions na to, z jednej:

extern void AddMapping<T,U>(Control control, T target, Func<T,U> mapping); 
extern void AddMapping<T,U>(Control control, T target, Expression<Func<T,U>> mapping); 

następnie wywołać ją z

this.AddMapping(this.myControl, myObject, (x => x.PropertyName)); 

Użyj argumentu Wyrażenie, jeśli chcesz rozebrać abstrakcyjne drzewo składniowe w czasie wykonywania, aby zrobić refleksyjne rzeczy, takie jak nazwa właściwości w postaci ciągu; ewentualnie, niech delegat wykona zadanie wyłudzania danych, których potrzebujesz.

3

Aby ułatwić z wyrażeniem oparty lambda obejście, napisałem go jako metodę rozszerzenia.

public static string GetPropertyName<T>(this object o, Expression<Func<T>> property) 
    { 
     var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo; 
     if (propertyInfo == null) 
      throw new ArgumentException("The lambda expression 'property' should point to a valid Property"); 
     var propertyName = propertyInfo.Name; 
     return propertyName; 
    } 

Zadzwoń jak tego

class testclass 
    { 
     public string s { get; set; } 
     public string s2 { get; set; } 
     public int i { get; set; } 

    } 

    [TestMethod] 
    public void TestMethod2() 
    { 
     testclass x = new testclass(); 
     string nameOfPropertyS = this.GetPropertyName(() => x.s); 
     Assert.AreEqual("s", nameOfPropertyS); 

     string nameOfPropertyI = x.GetPropertyName(() => x.i); 
     Assert.AreEqual("i", nameOfPropertyI); 

    } 

porządku, stosując jako metodę rozszerzenia jest naprawdę dla wygody, jak można rzeczywiście nazwać metodę na jednej klasie właściwości pylników klasy. Jestem pewien, że można to poprawić.

+0

Widzę kilka komentarzy związanych z korzystaniem z metody rozszerzenia, dlatego chciałem dostać się do tego przy WPF Binding (mvvm), aby móc wywołać OnPropertyChanged (this.GetProperty (() => MyProperty); pomaga złagodzić niektóre problemy związane z kompilacją czasu takiego wiązania wpf Przynajmniej jeśli zmienisz nazwę właściwości, uzyskasz trochę czasu na kompilację, musisz jednak edytować tekst wiązania w swoim xaml ... –

Powiązane problemy