På et nylig prosjekt fikk jeg i oppgave å omstrukturere store deler av et websystem. Det er skrevet i C#. Over tid hadde noen av code-behind-filene vokst til 4000 linjer. Målet var å få dette tallet ned til et mer vedlikeholdbart nivå.
I løpet av de neste innleggene har jeg tatt kodebiter som jeg omstrukturerte og vil forklare mine tanker og hvordan jeg kom fram til løsningen.
Det første kodeutdraget:
string tmp = Request.QueryString["st"];
_varStartRecNum = tmp;
if ((tmp != null) & (!Page.IsPostBack))
{
_varStartRecNum = tmp;
postBack = true;
}
tmp = Request.QueryString["det"];
if ((tmp != null) & (!Page.IsPostBack))
{
_varDetailsRecNum = tmp;
postBack = true;
}
tmp = Request.QueryString["return"];
if ((tmp != null) & (!Page.IsPostBack))
{
postBack = true;
}
tmp = Request.QueryString["searchnow"];
if ((tmp != null) & (!Page.IsPostBack))
{
Session["selectedTab"] = "mtf";
Session["sessionDSProviders"] = null;
Session["mtfs"] = null;
}
tmp = Request.QueryString["displaywalking"];
if (tmp == "true")
{
dispMtf = false;
postBack = true;
}
tmp = Request.QueryString["sb"];
if ((tmp != null) & (!Page.IsPostBack))
{
_varSortBy = tmp;
postBack = true;
switch (_varSortBy)
{
case "Distance":
case "Drive time":
ddlSortBy.SelectedIndex = 0;
break;
case "Name":
ddlSortBy.SelectedIndex = 1;
break;
case "Gender":
ddlSortBy.SelectedIndex = 2;
break;
case "Clinic":
ddlSortBy.SelectedIndex = 3;
break;
case "City":
ddlSortBy.SelectedIndex = 4;
break;
case "Description":
ddlSortBy.SelectedIndex = 5;
break;
}
}
Kodeutdraget ovenfor er en samling av if-setninger, som er en evaluering og en utførelse. I mitt første forsøk prøvde jeg å bruke samme evaluering for alle if-setninger, men så innså jeg at en var annerledes. Uten å forstå hensikten med koden, er jeg tvunget til å bevare logikken ordrett.
Annen if-evaluering:
tmp = Request.QueryString["displaywalking"];
if (tmp == "true")
{
dispMtf = false;
postBack = true;
}
Switch-setningen bekymret meg. Betingelsen for å gå inn i switch-setningen er den samme som de andre. Jeg bestemte meg for å fortsette og bekymre meg om switch-setningen senere.
Koden bruker samme variabel, ‘tmp’-variabelen, for å hente ulike spørringsverdier. Verdien overskrives med hver spørringshenting. For klarhet opprettet jeg en variabel for hver spørringverdi:
string st = Request.QueryString["st"];
string det = Request.QueryString["det"];
string @return = Request.QueryString["return"];
string searchNow = Request.QueryString["searchnow"];
string displayWaling = Request.QueryString["displaywalking"];
string sb = Request.QueryString["sb"];
Neste trinn var å isolere evalueringen og uttrykket mens jeg holdt dem forbundet med hverandre. Hvis en evaluering er sann, vil jeg utføre sitt tilsvarende uttrykk. Jeg opprettet en klasse som representerte foreningen.
private class Evaluate
{
public Func Evaluation { get; set; }
public Action Expression { get; set; }
}
Nå kan jeg opprette en evaluering, og hvis den er sann, kan jeg utføre sitt uttrykk.
Neste problem var hvordan bruke klassen ovenfor med alle if-setningene. Jeg var bekymret for at uttrykkene kunne bli uhandterlige i en samling. Hele formålet var å skape en kortfattet, skalerbar løsning. Den eksisterende løsningen var verken det ene eller det andre.
var eval = new[]
{
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(st) && !IsPostBack), Expression = () => { _varStartRecNum = st;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(det) && !IsPostBack), Expression = () => { _varStartRecNum = det;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(@return) && !IsPostBack), Expression = () => {postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(searchNow) && !IsPostBack), Expression = () => {Session["selectedTab"] = "mtf";Session["sessionDSProviders"] = null; Session["mtfs"] = null;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(displayWaling)), Expression = () => {dispMtf = false; postBack = true;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(sb) && !IsPostBack), Expression = () => {_varSortBy = sb;postBack = true; SetSort(_varSortBy);}},
};
Det viste seg å være bedre enn jeg forventet. En ulempe med min løsning er at hvis du ikke vet hvordan du bruker delegater, vil du være i trøbbel når det gjelder vedlikehold av koden ovenfor.
Det siste steinfallet var switch-setningen. Den skulle ikke passe elegant inn i min anonyme samling, men det trengte den ikke:
private void SetSort(string sortBy)
{
switch (sortBy)
{
case "Distance":
case "Drive time":
ddlSortBy.SelectedIndex = 0;
break;
case "Name":
ddlSortBy.SelectedIndex = 1;
break;
case "Gender":
ddlSortBy.SelectedIndex = 2;
break;
case "Clinic":
ddlSortBy.SelectedIndex = 3;
break;
case "City":
ddlSortBy.SelectedIndex = 4;
break;
case "Description":
ddlSortBy.SelectedIndex = 5;
break;
}
}
Ved å innkapsle den i en metode, kunne jeg referere til metoden i uttrykket. Det fungerte veldig bra.
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(sb) && !IsPostBack), Expression = () => {_varSortBy = sb;postBack = true; SetSort(_varSortBy);}
Den siste komponenten er iterasjon over samlingen:
foreach (var evaluate in eval.Where(evaluate => evaluate.Evaluation()))
{
evaluate.Expression();
}
Den komplette løsningen:
private class Evaluate
{
public Func Evaluation { get; set; }
public Action Expression { get; set; }
}
private void SetSort(string sortBy)
{
switch (sortBy)
{
case "Distance":
case "Drive time":
ddlSortBy.SelectedIndex = 0;
break;
case "Name":
ddlSortBy.SelectedIndex = 1;
break;
case "Gender":
ddlSortBy.SelectedIndex = 2;
break;
case "Clinic":
ddlSortBy.SelectedIndex = 3;
break;
case "City":
ddlSortBy.SelectedIndex = 4;
break;
case "Description":
ddlSortBy.SelectedIndex = 5;
break;
}
}
private void EvaluateQueryParameters()
{
string st = Request.QueryString["st"];
string det = Request.QueryString["det"];
string @return = Request.QueryString["return"];
string searchNow = Request.QueryString["searchnow"];
string displayWaling = Request.QueryString["displaywalking"];
string sb = Request.QueryString["sb"];
var eval = new[]
{
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(st) && !IsPostBack), Expression = () => { _varStartRecNum = st;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(det) && !IsPostBack), Expression = () => { _varStartRecNum = det;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(@return) && !IsPostBack), Expression = () => {postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(searchNow) && !IsPostBack), Expression = () => {Session["selectedTab"] = "mtf";Session["sessionDSProviders"] = null; Session["mtfs"] = null;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(displayWaling)), Expression = () => {dispMtf = false; postBack = true;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(sb) && !IsPostBack), Expression = () => {_varSortBy = sb;postBack = true; SetSort(_varSortBy);}},
};
foreach (var evaluate in eval.Where(evaluate => evaluate.Evaluation()))
{
evaluate.Expression();
}
}
Til slutt liker jeg denne løsningen bedre enn originalen. En av ulempene er nivået den er skrevet på. Jeg ønsket å skape en enklere løsning som enhver utvikler kunne vedlikeholde. Det er ikke noe vanskelig med koden ovenfor; jeg oppretter en samling og itererer over den. Forvirringen kommer fra evalueringen og uttrykkene. Det er ikke et nybegynnertema.
Forfatter: Chuck Conway er en AI-ingeniør med nesten 30 års erfaring innen programvareutvikling. Han bygger praktiske AI-systemer—innholdspipelines, infrastrukturagenter og verktøy som løser virkelige problemer—og deler det han lærer underveis. Koble til ham på sosiale medier: X (@chuckconway) eller besøk ham på YouTube og på SubStack.