Скажем, у меня есть класс Customer
с некоторыми свойствами:
public class Customer
{
public string CustAddr = GetCustAddr(); //Long procedure returning address
public double CustAcct = GetCustAcct(); //Long procedure returning account
public string CustInvoice = GetCustInvoice(); //Long procedure returning invoice
}
Этот класс возвращается через функцию:
public Customer GetData(string query)
{
Customer cust = new Customer();
//set the values for each of the properties
return cust;
}
Сейчас он возвращает весь класс, и я могу его использовать следующим образом:
lblDisplay = GetData("QUERY").CustAddr.ToString();
Однако предположим, что каждому свойству требуется много времени для вычисления. Если мне нужно только значение CustAddr, оно все равно вычисляется и доступно для CustAcct
и CustInvoice
.
Как мне изменить свою функцию, чтобы вернуть только свойство, которое я ищу, кроме того, чтобы разбить мой класс на отдельные процедуры для вызова? Например, я мог бы просто:
lblDisplay = GetCustAddr().ToString();
но это не то, что я ищу. Я думаю, что лучше иметь все мои данные в организованной структуре, а не кучу разных процедур.
Это отличный кандидат на ленивую инициализацию. Здесь я представляю пример использования свойств (у вас есть поля).
public class Customer
{
public Lazy<string> CustAddr { get; private set; }
public Lazy<double> CustAcct { get; private set; }
public Lazy<string> CustInvoice { get; private set; }
public Customer()
{
CustAddr = new Lazy<string>(GetCustAddr);
CustAcct = new Lazy<double>(GetCustAcct);
CustInvoice = new Lazy<string>(GetCustInvoice);
}
}
Однако я бы отказался, если бы не указал, что вам не следует использовать типы с плавающей точкой (float
, double
) для хранения денежных значений. Вместо этого используйте decimal
.
double
вместо decimal
но вы не упоминаете тот факт, что он выставляет открытые поля, а не свойства?
GetData
.
Зачем использовать экзотическое решение, когда есть ванильный?
Реализация расчета на get
свойств.
NB: у вас есть публичные поля, а не свойства
Очень простое решение (ничего экзотического!)
Смотрите эту скрипку
например
public class Customer
{
private double ? _custAcct = null;
public double CustAcct
{
get
{
if (!_custAcct.HasValue)
{
_custAcct = GetCustAcct();
}
return _custAcct.Value;
}
}
private double GetCustAcct()
{
// do something that takes a long time
return 1234.45;
}
}
То, о чем вы говорите, это ленивая загрузка или ленивая инициализация. Вы пишете свои свойства примерно так:
public class MyLazyWidget
{
. . .
public BigExpensiveObject MyLazyProperty
{
get
{
if ( BigExpensiveObjectBackingStore == null )
{
BigExpensiveObjectBackingStore = ExpensiveOperation() ;
}
return BigExpensiveObjectBackingStore ;
}
}
private static BigExpensiveObjectBackingStore = null ;
. . .
}
И если ваше приложение многопоточное, вам нужно будет беспокоиться о состоянии гонки, поэтому вам нужно синхронизировать доступ к хранилищу статических резервных копий:
public class MyLazyWidget
{
. . .
public BigExpensiveObject MyLazyProperty
{
get
{
lock( MyLazyPropertyLatch )
{
if ( BigExpensiveObjectBackingStore == null )
{
BigExpensiveObjectBackingStore = ExpensiveOperation() ;
}
}
return BigExpensiveObjectBackingStore ;
}
}
private static readonly object MyLazyPropertyLatch = new object() ;
private static BigExpensiveObjectBackingStore = null ;
. . .
}
Lazy<T>
позаботится о защелке для вас.
Lazy<T>
также немного лаконичнее.