I have an abstract base class Bank
and its successors BankOfAmerica: Bank
and JPMorganChase: Bank
. I want to make one of them default in case of creation BankAccount
instance without indication exact Bank
in BankAccount
constructor, so I created a static class GeneralBankConfig
with DefaultBank
field (or property? or method?).
Which of the following ways is better and why?
public static Bank DefaultBank { get; } = new BankOfAmerica();
public static Bank DefaultBank { get { return new BankOfAmerica(); } }
public static readonly Bank DefaultBank = new BankOfAmerica();
public static Bank GetDefaultBank() { return new BankOfAmerica(); }
Is it a good way to store configurations?
To understand the differences, it helps to look at the compiled C#, with unique names so that all four implementations can live side-by-side.
public static class GeneralBankConfig
{
public static Bank DefaultBank1 { get; } = new BankOfAmerica();
public static Bank DefaultBank2 { get { return new BankOfAmerica(); } }
public static readonly Bank DefaultBank3 = new BankOfAmerica();
public static Bank GetDefaultBank4() { return new BankOfAmerica(); }
}
public abstract class Bank { }
public class BankOfAmerica : Bank { }
This compiles to the following:
public static class GeneralBankConfig
{
[CompilerGenerated]
private static readonly Bank <DefaultBank1>k__BackingField = new BankOfAmerica();
public static readonly Bank DefaultBank3 = new BankOfAmerica();
public static Bank DefaultBank1
{
[CompilerGenerated]
get
{
return <DefaultBank1>k__BackingField;
}
}
public static Bank DefaultBank2
{
get
{
return new BankOfAmerica();
}
}
public static Bank GetDefaultBank4()
{
return new BankOfAmerica();
}
}
public abstract class Bank
{
}
public class BankOfAmerica : Bank
{
}
Option 1 compiles to a read only public property with a compile-generated backing field. This is typically the most common way to express public apis in instance classes since they can be exposed via interfaces. However, for static properties, that becomes more of a preference, although there may be a slight additional cost for invoking the get_DefaultBank1()
method under the hood as opposed to referencing the static field directly.
Option 2 compiles to a public readonly property that returns a new BankOfAmerica
instance every time it is called. This is most likely the opposite of what you want since you are no longer using a "cached" instance.
Option 3 compiles to a public readonly field. See the notes on option 1.
Option 4 compiles to a public static method that returns a new instance of BankOfAmerica
every time it is called. This is the worst option since not only does it create a new object instance, but there are costs to calling the method that do not exist when referencing a field.
You can see the IL for all four invocations here:
IL_0001 call GeneralBankConfig.get_DefaultBank1 ()
IL_0006 stloc.0 // defaultBank1
IL_0007 call GeneralBankConfig.get_DefaultBank2 ()
IL_000C stloc.1 // defaultBank2
IL_000D ldsfld GeneralBankConfig.DefaultBank3
IL_0012 stloc.2 // defaultBank3
IL_0013 call GeneralBankConfig.GetDefaultBank4 ()
IL_0018 stloc.3 // defaultBank4
In short, choose option 1 or 3, depending on whether you'd prefer to expose a field or property.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.