Perché Session si è implementata in questo modo in Asp.net

3

Non sono uno sviluppatore di Asp.net/C# ma di recente ho dovuto ridefinire leggermente un progetto di Asp.net/C# e a un certo punto ho dovuto usare Session . Quando lavoravo con la sessione, indipendentemente dal tipo di dati che stavo specificando per la variabile di sessione, ho dovuto eseguire il cast della variabile di sessione ogni volta che dovevo accedervi.

Session["index"] = 0;
Session["index"] = Session["index"] + 1; // throws exception
Session["index"] = ((int)Session["index"]) + 1; // it works here

Chiedendo ai miei colleghi sviluppatori di C #, sembra che il Session sia in qualche modo un oggetto che copre il tipo di dati effettivo della variabile, apparentemente senza perderlo, ma per qualche motivo devi comunque lanciarlo comunque ogni volta che vuoi accedervi.

Non sono sicuro che sia così o no, anche se l'ho capito correttamente, ma quello che non capisco è perché debba essere implementato in modo che lo sviluppatore debba lanciarlo prima di usarlo . Come dicono i miei colleghi, è perché in pratica puoi avere un oggetto di sessione tipizzato dinamicamente, in fase di esecuzione.

Quello che sto pensando è, in primo luogo, perché è necessario disporre di tale funzionalità solo per la sessione, in un linguaggio tipizzato in modo statico come Asp.net/C#? Ad esempio, qual è il caso di utilizzo della definizione di una variabile "sessione" come un numero intero, ma in seguito inserire una stringa al momento dell'esecuzione? Esiste un caso pratico e un requisito per tale funzione, non solo in Asp.net ma in qualsiasi altra lingua?

In secondo luogo, se supponiamo che anche le variabili di sessione debbano essere tipizzate staticamente, allora è "tecnicamente" possibile implementare la sessione di Asp.net in modo tale che quando si definisce una variabile di sessione come di seguito, il compilatore alloca la memoria nell'heap, tieni il tipo di dati accanto ad esso e semplicemente elimina la necessità di lanciarlo ogni volta?

Session["index"] = 0; // integer type, available at compile-time

Che cosa accadrebbe se provassi ad assegnare una stringa a questa variabile intera? Bene, come tutto il resto in un linguaggio tipizzato staticamente, otterrai un'eccezione.

Mi manca qualcosa qui? Semplicemente non riesco a capire perché una tale decisione di progettazione sia stata presa dal team di sviluppo di Asp.net e da come lo sviluppatore potrebbe trarne vantaggio. Ci si chiede anche se ci sia qualcosa di correlato al modo in cui altri linguaggi come Java o C ++ hanno implementato le sessioni, direttamente nella lingua stessa o tramite una libreria, quindi ha portato anche il team di Asp.net a implementare una sessione del genere?

Aggiornamento # 1

Solo per chiarire l'aria, la mia domanda principale è perché il Session è stato implementato in questo modo? Quali sono i vantaggi di avere una sessione come questa - qualunque essa sia, piuttosto come è stata implementata - anche se sto cercando di sapere anche quello.

Aggiornamento n. 2

Per quanto riguarda il commento @JacquesB: "Devi essere in grado di salvare tutti i tipi di oggetti diversi in una Session, quindi il tipo deve essere Object, non c'è altra opzione" ; Perché il seguente codice:

Session["index"] = 0;
Session["name"] = "abc";

Non può essere tradotto, dal compilatore, in fase di compilazione, a qualcosa di simile a questo:

int SessionIndex = 0;
string SessionName = "abc";

Non capisco perché "non c'è altra opzione". Dopo tutto, è un programma per computer, non qualcosa di magico, o mi manca ancora qualcosa?

    
posta Mahdi 20.08.2015 - 19:26
fonte

3 risposte

8

Il problema di fondo non è specifico di Session o di Asp.Net, è un problema fondamentale nel funzionamento delle raccolte in linguaggi tipizzati staticamente. L'oggetto Session è progettato per consentire di archiviare oggetti di qualsiasi tipo. Ciò significa che il tipo statico degli elementi memorizzati deve essere Object . Quindi Session equivale a Dictionary<string, Object> . Poiché il compilatore può solo sapere che il tipo dell'articolo è Object , devi eseguire il cast esplicito su un tipo più specifico per eseguire qualsiasi operazione (e il cast potrebbe ovviamente fallire in fase di esecuzione se si ottiene il tipo sbagliato. )

Ora ti chiedi perché il compilatore non è abbastanza intelligente da riconoscerlo:

Session["name"] = "abc";

significa che la voce con il "nome" della chiave sarà di tipo string . Questo non può funzionare perché il nome della chiave è un'espressione con un valore che può essere sconosciuto al momento della compilazione. Eg.

Session[Datetime.Now.ToString()] = "abc";

Non c'è modo in cui il compilatore possa capirlo nel caso generale, anche se è teoricamente possibile in alcuni casi molto specifici.

Per spiegare un po 'più in generale: devi distinguere tra il tipo di un valore in runtime e il tipo che il compilatore è in grado di determinare in tempo di compilazione .

Un valore ha sempre un tipo specifico in fase di esecuzione e questo tipo è (come suggerisci) memorizzato insieme al valore, quindi puoi sempre controllare il tipo effettivo di un valore con il metodo GetType() .

Ma in un linguaggio tipizzato in modo statico, il controllo del tipo avviene al momento della compilazione, ea quel punto il compilatore non è sempre in grado di conoscere il tipo effettivo di tutti i valori. Prendi questo esempio:

object x = "abs";
int l = x.Length; // !Compile error

In fase di esecuzione, il tipo del valore in x è String , ma il compilatore deve fare affidamento sul tipo dichiarato di x con is Object . E poiché Object non ha la proprietà Length , ottieni un errore di compilazione.

Ora potresti pensare che il compilatore dovrebbe essere abbastanza intelligente da rendersi conto che x è in realtà un String in questo caso, ma questo non funzionerà nel caso generale, poiché x potrebbe essere assegnato dire un numero intero in una parte diversa di il programma, quindi il tipo effettivo potrebbe cambiare durante l'esecuzione del programma. L'unica cosa che il compilatore può garantire è che il tipo di x sarà Object o un sottotipo di Object, perché questo è il tipo dichiarato.

In questo caso particolare conosci più del compilatore, perché ti rendi conto che x è un String , anche se il tipo dichiarato è meno specifico. Qui è dove possiamo usare un cast: quando sappiamo che il tipo di runtime è migliore del compilatore. Un cast non cambia il tipo di un valore, ma semplicemente informa il compilatore di assumere un certo tipo più specifico. Quindi puoi scrivere:

int l = ((string)x).Length;

Un cast naturalmente fallirà in fase di esecuzione nel caso in cui il tipo effettivo del valore in x non sia una stringa.

    
risposta data 21.08.2015 - 10:27
fonte
4

Ciò che stai suggerendo non è possibile, perché il tipo delle variabili assegnate non può essere conosciuto fino al runtime. Ricorda che la sessione è effettivamente condivisa tra tutti i moduli utilizzati nella creazione della pagina. Alcuni di questi potrebbero non essere noti in fase di compilazione. Pertanto, è necessario specificare il tipo o spostare il controllo in runtime utilizzando l'oggetto o dinamico.

Ad esempio, che cosa farà il compilatore con quanto segue?

public void AssignString()
{
      Session["test"] = "STRING";
}

public void AssignInt()
{
      Session["test"] = 10;
}

I due metodi potrebbero essere chiamati in qualsiasi ordine. Queste potrebbero anche essere una funzione di libreria in diversi plugin che vengono caricati dinamicamente in fase di esecuzione.

    
risposta data 20.08.2015 - 22:41
fonte
2

Session è effettivamente una mappa / dizionario con una chiave che è un string e un valore che è un object . Precede i tipi generici in C # / ASP.Net, e sarebbe più probabilmente un IDictionary<string,dynamic> oggi, che supporterà ciò che stai cercando di fare.

//you cannot do this either...
//default from a session is an object/null, not even an integer
object foo = Session["index"];
foo = foo + 1;

Se usi C # più recente (come molti anni fa), con il supporto per la parola chiave as , dovresti probabilmente fare qualcosa del tipo ...

Session["index"] = (Session["index"] as int?).GetValueOrDefault() + 1;

Quale cast il risultato da Session["index"] a un numero intero nullable (o null se c'è una mancata corrispondenza), prendendo il valore predefinito o il valore di istanza se corrispondente, quindi aggiungendo 1.

Per inciso, in generale non fare affidamento sullo stato di una sessione se puoi evitarlo, di solito è meglio fare affidamento sul lato client localStorage o sessionStorage e / o includere tali dati in qualsiasi richiesta che in realtà ne hanno bisogno. La sessione usa se stesso serializza tutte le richieste simultanee per un dato utente / sessione. Per non parlare della necessità di un server / archivio di sessione se si sta scalando oltre un singolo server.

    
risposta data 20.08.2015 - 19:50
fonte

Leggi altre domande sui tag