2009-08-13 4 views
18

Ich bin sehr neu in C# so bitte Geduld mit mir ...C#: Wie wird der Standardwert für eine Eigenschaft in einer partiellen Klasse festgelegt?

Ich bin eine partielle Klasse Implementierung und möchte zwei Eigenschaften hinzufügen wie folgt:

public partial class SomeModel 
{ 
    public bool IsSomething { get; set; } 
    public List<string> SomeList { get; set; } 

    ... Additional methods using the above data members ... 
} 

Ich möchte initialisiere beide Datenelemente: IsSomething bis True und SomeList bis new List<string>(). Normalerweise würde ich es in einem Konstruktor tun, aber weil es eine partielle Klasse ist, möchte ich den Konstruktor nicht berühren (sollte ich?).

Was ist der beste Weg, dies zu erreichen?

Dank

PS Ich bin in ASP.NET MVC arbeiten, Funktionalität ein ein bestimmtes Modell hinzugefügt, damit die Teilklasse.

+2

Das sind alrea dy die Standardwerte für diese Typen. Du musst nichts tun. –

+0

möchte ich explizit machen. Was, wenn ich "True" oder "New List ()" wollte? –

+1

Ich habe die Frage bearbeitet, um Werte wiederzugeben, die nicht die "natürlichen" Standardwerte sind. –

Antwort

34

Aktualisiert für C# 6

C# hat 6 die Möglichkeit hinzugefügt, einen Standardwert auto-Eigenschaften zuweisen. Der Wert kann ein beliebiger Ausdruck sein (er muss keine Konstante sein). Hier ein paar Beispiele:

// Initialize to a string literal 
public string SomeProperty {get;set;} = "This is the default value"; 

// Initialize with a simple expression 
public DateTime ConstructedAt {get;} = DateTime.Now; 

// Initialize with a conditional expression 
public bool IsFoo { get; } = SomeClass.SomeProperty ? true : false; 

Original-Antwort

automatisch implementierten Eigenschaften können im Konstruktor der Klasse initialisiert werden, aber nicht auf dem propery selbst.

public SomeModel 
{ 
    IsSomething = false; 
    SomeList = new List<string>(); 
} 

... oder Sie können ein Feld gesicherte Eigenschaft (etwas mehr Arbeit) und initialisieren das Feld selbst verwenden ...

private bool _IsSomething = false; 
public bool IsSomething 
{ 
    get { return _IsSomething; } 
    set { _IsSomething = value; } 
} 

Update: Meine oben Antwort nicht klären das Problem, dass es in einer partiellen Klasse ist. Mehrdad's answer bietet die Lösung der Verwendung einer partiellen Methode, die mit meinem ersten Vorschlag übereinstimmt. Mein zweiter Vorschlag, nicht automatisch implementierte Eigenschaften (manuell implementierte Eigenschaften?) Zu verwenden, funktioniert in dieser Situation.

+0

SomeList = neue Liste **() **; – grenade

+0

In Bezug auf Ihren ersten Vorschlag, wird es als "gute Praxis" angesehen, dies zu tun? Es wird sicherlich einfacher, aber fühlt sich an wie "Code-Geruch" ... –

+0

@RaxL Ich bin auf dem Zaun über den Geruch davon. Die Initialisierungslogik ist ein ziemlich normaler Teil der OO-Entwicklung; vorausgesetzt, dass die Entwickler, die an dem System arbeiten, die gleichen Praktiken befolgen, dann würde ich nicht glauben, dass es ein Problem wäre. – STW

8

Die erste Eigenschaft (IsSomething) ist ein boolescher Wert. Es wird standardmäßig falsch sein.

Die zweite Eigenschaft, da es sich um einen Referenztyp handelt, wird standardmäßig auf Null zurückgesetzt, ohne dass Sie dafür etwas unternehmen müssen. Sie müssen den Konstruktor nicht berühren, da Referenztypen (Klassen) in .NET automatisch als null beginnen.

Wenn Sie einen Nicht-Standardwert verwenden wollen, dann würden Sie zwei Möglichkeiten -

zunächst ein Trägerspeicherfeld verwenden:

private bool isSomething = true; 
public bool IsSomething { 
    get { return this.isSomething; } 
    set { this.isSomething = value; } 
} 

Zweite Option - es an den Konstruktor hinzuzufügen.

Beachten Sie, dass die erste Option keinen zusätzlichen Aufwand hat - im Grunde ist es der Compiler, wenn Sie eine automatische Eigenschaft verwenden.

+0

+1 für die verschiedenen Verhaltensweisen von Wert/Referenztypen. – STW

1

Ihre beiden Eigenschaften haben bereits die von Ihnen benötigten Standardwerte.

Es ist nichts falsch daran, einen Konstruktor in einer partiellen Klasse zu haben. Teilklassen sind in keiner Weise besonders, abgesehen davon, dass ihr Quellcode auf mehrere Dateien/Deklarationen verteilt ist.

+1

Wie Reed in seinem Kommentar darauf hingewiesen hat, werden die Werttypen mit einem Standardwert initialisiert (0 für int, false für bool ...), aber die Referenztypen werden auf null/Nothing initialisiert. Also in seinem Fall IsSomething = false und SomeList = null – STW

+0

@Yooder: diese Antwort wurde zur Verfügung gestellt, wenn die Frage noch nach den Standardwerten von False und null fragte. Bitte ziehe deine -1 zurück, es ist unfair für @Programming Hero –

+0

Die Torpfosten während des Spiels verschieben? Nicht fair! –

5

Sie können nicht zwei Konstruktoren in zwei Teilen einer partiellen Klasse haben. Sie können jedoch partial methods verwenden etwas wie es zu erreichen:

// file1: 
partial void Initialize(); 
public Constructor() { 
    // ... stuff ... initialize part 1 
    Initialize(); 
} 

// file2: 
void Initalize() { 
    // ... further initializations part 2 might want to do 
} 

Wenn keine Teile einer Teilklasse die partielle Methode definiert, werden alle Anrufe an, es würde entfallen.

+0

Leider hilft das nicht, wenn der Teil der Klasse, der den Konstruktor hat, generierter Code ist. – Vaccano

4

Um dies zu, verwenden Sie keine automatische Eigenschaft aber auf die alte Weise

YourType _yourParameter = yourDefaultValue; 
public YourType YourParameter 
{ 
    get{return _yourParameter;} 
    set{_yourParameter=value;} 
} 
5

WARNUNG für die Benutzer von WCF Teilklassen

Wenn Sie versuchen, eine Eigenschaft auf einen WCF-Proxy hinzufügen Klasse (generiert von Add Service Reference) möglicherweise überrascht, dass private Felder nicht initialisiert werden, da anscheinend no constructor at all is called. Das hat nichts mit

private bool _sendEmail = true; 

zu tun, ob das Feld in einer Teilklasse ist oder nicht:

Wenn Sie dies zu tun versuchen (wie in einigen anderen Antworten vorgeschlagen) ist es nicht immer erhalten genannt.

Sie müssen ein [OnDeserialized] Attribut hinzufügen, mit dem Sie das Objekt weiter initialisieren können. Dies ist Teil von System.Runtime.Serialization und ist daher nur im Kontext der Serialisierung bei Verwendung von DataContractSerializer nützlich.

public partial class EndOfDayPackageInfo 
{ 
    [OnDeserialized()] 
    public void Init(StreamingContext context) 
    { 
     _sendEmail = true; 
    } 

    private bool _sendEmail; 
    public bool SendEmail 
    { 
     get 
     { 
      return _sendEmail; 
     } 
     set 
     { 
      _sendEmail = value; 
      RaisePropertyChanged("SendEmail"); 
     } 
    } 

}

Ein weiterer Ansatz ist die 'lazy load' die Eigenschaft - aber dieser Ansatz ist viel weniger elegant.

private bool _sendEmail; 
    private bool _sendEmailInitialized; 

    public bool SendEmail 
    { 
     get 
     { 
      if (!_sendEmailInitialized) 
      { 
       _sendEmailInitialized = true; 
       _sendEmail = true; // default value 
      } 

      return _sendEmail; 
     } 
     set 
     { 
      if (!_sendEmailInitialized) 
      { 
       // prevent unwanted initialization if 'set' is called before 'get' 
       _sendEmailInitialized = true; 
      } 

      _sendEmail = value; 
      RaisePropertyChanged("SendEmail"); 
     } 
    } 
+0

Wie interessant. Macht Sinn in einer verdrehten Weise. – NotMe

+0

ya aber zuerst sehr verwirrend. habe das heute entdeckt und dachte, es wäre ein WPF-bindendes Problem, bis ich schließlich erkannte, dass es WCF war. stellt sich heraus, dass sie diese Methode aufrufen, die den Aufruf eines Konstruktors umgeht: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx –

+0

Danke, das war genau mein Problem. –

2

Für Benutzer der Version 6.0 von C#, dann ist es möglich, die Eigenschaften wie folgt zu initialisieren:

public bool IsSomething { get; set; } = true; 
public List<string> SomeList { get; set; } = new List<string>(); 
0
private bool _InternalUserContactUpdate = false; 
     public bool InternalUserContactUpdate 
     { 
      get { return _InternalUserContactUpdate; } 
      set { _InternalUserContactUpdate = value; } 
     } 

Dann, wenn Sie den Wert unter der Bedingung außer Kraft setzen möchten,

if(!objUserModel.FirstName.ToLower().Equals(entry.Key[0].Attributes.Contains("firstname").ToString().ToLower())) 
     { 
      objUserModel.InternalUserContactUpdate= true; 
     } 

Hoffe, das wird helfen

Verwandte Themen