2015-01-12 15 views
17

nameof (order.User.Age) restituisce solo "Age" anziché "order.User.Age"Perché il nome restituisce solo il cognome?

Qual è il motivo per farlo in modo più limitato? Se vogliamo solo il cognome che potevamo fare qualcosa di simile

public static GetLastName(this string x) { 
    return string.Split(x, '.').Last(); 
} 
nameof(order.User.Age).GetLastName() 

E con un solo operatore siamo riusciti a ottenere entrambe le cose, "Age" e "order.User.Age". Ma con l'implementazione corrente possiamo solo ottenere "Età".

C'è qualche logica dietro questa decisione?

Edit: Per esempio, tale comportamento è necessario per MVC vincolante

Html.TextBox(nameof(order.User.Age)) 
+2

Si noti che 'order.User' può anche essere una funzione che restituisce un oggetto con proprietà' Nome'. A cosa dovrebbe fare il nome in questi casi? – AlexR

+0

'nameof' è una costante di tempo di compilazione, quindi come funzionerebbe su un'istanza? – leppie

+0

Per sapere perché, dovresti passare attraverso le lunghe discussioni su http://roslyn.codeplex.com/ –

risposta

3

Tutte fini dell'utilizzo nameof bisogno solo l'ultimo "nome" dell'espressione.

Per esempio nameof parametro quando gettando ArgumentNullException: collega

void Method(string parameter) 
{ 
    if (parameter == null) throw new ArgumentNullException(nameof(parameter)); 
} 

MVC azione

<%= Html.ActionLink("Sign up", 
    @typeof(UserController), 
    @nameof(UserController.SignUp)) 
%> 

INotifyPropertyChanged

int p { 
    get { return this._p; } 
    set { this._p = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.p)); } 
} 

Maggiori informazioni: https://roslyn.codeplex.com/discussions/570551

+0

E il binding MVC Html.TextBox (nameof (User.Name))? – ais

+4

Umm, "tutti gli scopi"? No, direi il contrario. Ad esempio, quando si incontra un riferimento null imprevisto e si desidera registrare un errore, ma non si desidera generare un'eccezione, si desidera fornire il maggior numero possibile di contesto su cosa esattamente fosse null. Prendi questo esempio: Instance.Window.TextLabel.TextField.StringLabel.Value.Reference.Object. Supponiamo che "Oggetto" sia nullo. Quale sarebbe più utile per la diagnostica ?: Solo "Oggetto" o "Instance.Window.TextLabel.TextField.StringLabel.Value.Reference.Object"? – Hatchling

+2

Direi che null è qualcosa di diverso tutti insieme, ma se si guardano le casse di pane e burro elencate nel link, anche Logging è lì, sulla base di ciò, il tuo caso verrebbe probabilmente registrato in questo modo: 'MyMethod (InsaneTypeThatIsNull myVar) {Log (nameof (MyMethod), $ "{nameof (myVar)} era null"); } 'È facile tornare indietro e trovare il tipo – FRoZeN

6

Perché è esattamente quello che è stato inventato. Come si può leggere in already linked discussions, qui si utilizza l'operatore nameof come nameof(member-access), della forma E.I<A1…AK>, che restituirà:

Questi casi sono tutti risolti utilizzando le regole per una semplice ricerca del nome $ 7.6.2 o membro accedere a $ 7.6.4. Se riescono a impegnarsi, devono associarsi a:

  • Un metodo-gruppo. Questo produce un errore "Per specificare il nome di un metodo, è necessario fornire i suoi argomenti".
  • Variabile, valore, parametro, costante, membro di enumerazione, accesso proprietà, campo, evento, tipo parametro, spazio dei nomi o tipo. In questo caso il risultato dell'operatore nameof è semplicemente "I", che è generalmente il nome del simbolo a cui è associato l'argomento.Ci sono alcune avvertenze ...

Quindi, in questo caso, per sua definizione, deve valutare tutte le espressioni prima tutti i puntini, passo dopo passo, e dopo che valutano l'ultimo a ottenere il suo Name :

order.User.Age --> User.Age --> Age 
0

Date un'occhiata a questo metodo tratto da:

https://github.com/okhosting/OKHOSTING.Data/blob/master/src/PCL/OKHOSTING.Data/Validation/MemberExpression.cs

public static string GetMemberString(System.Linq.Expressions.Expression<Func<T, object>> member) 
    { 
     if (member == null) 
     { 
      throw new ArgumentNullException("member"); 
     } 

     var propertyRefExpr = member.Body; 
     var memberExpr = propertyRefExpr as System.Linq.Expressions.MemberExpression; 

     if (memberExpr == null) 
     { 
      var unaryExpr = propertyRefExpr as System.Linq.Expressions.UnaryExpression; 

      if (unaryExpr != null && unaryExpr.NodeType == System.Linq.Expressions.ExpressionType.Convert) 
      { 
       memberExpr = unaryExpr.Operand as System.Linq.Expressions.MemberExpression; 

       if(memberExpr != null) 
       { 
        return memberExpr.Member.Name; 
       } 
      } 
     } 
     else 
     { 
      //gets something line "m.Field1.Field2.Field3", from here we just remove the prefix "m." 
      string body = member.Body.ToString(); 
      return body.Substring(body.IndexOf('.') + 1); 
     } 

     throw new ArgumentException("No property reference expression was found.", "member"); 
    } 
11

Nota che se avete bisogno/desidera che il nome "pieno", si potrebbe fare questo:

$"{nameof(order)}.{nameof(User)}.{nameof(Age)}".GetLastName(); 

fintanto che tutti questi nomi sono nell'ambito corrente.

Ovviamente in questo caso non è molto utile (i nomi non saranno inclusi nella chiamata Razor), ma potrebbe essere se fosse necessario, ad esempio, il nome completo dello spazio dei nomi completo di un tipo per un chiama allo Type.GetType() o qualcosa del genere.

Se i nomi non sono di portata, si potrebbe ancora fare un po 'più il goffo:

$"{nameof(order)}.{nameof(order.User)}.{nameof(order.User.Age)}".GetLastName(); 

- anche se è probabile che almeno uno di questi dovrebbe essere di portata (a meno che non User.Age è una struttura statica) .

+2

Questo non funziona poiché' nameof' deve essere pienamente qualificato. Sembrerebbe quindi come '$" {nomeof (ordine)}. {Nomeof (ordine.utile)}. {Nomeof (ordine.utile.area)} "", che indica esattamente il punto dell'OP. –

+2

Questo funziona assolutamente - il nome di non ha bisogno di essere pienamente qualificato, i parametri devono essere inclusi nella portata. Potrei aver assunto che tutti questi nomi fossero in ambito, ma ciò non significa che non funzioni. Ovviamente, se stai cercando di usarlo in un ambito diverso, è necessario che tu sia qualificato, ma non vedo come ciò influenzi realmente la risposta. –

+1

Potrei averlo espresso in modo errato affermando "pienamente qualificato". Tuttavia, influisce sulla risposta poiché dalla mia lettura dell'OP, non sono tutti in ambito. –