In my NET MAUI application I am de-serializing a http response:
private async Task<T> SerializeResponse<T>(HttpContent content)
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
using var stream = await content.ReadAsStreamAsync();
var result = await JsonSerializer.DeserializeAsync<T>(stream, options);
return result;
}
In this special case T is type of List, like:
public partial class BaseViewModel : ObservableValidator
{
public event NotifyWithValidationMessages? ValidationCompleted;
public virtual ICommand ValidateCommand => new RelayCommand(() => ValidateModel());
public BaseViewModel()
{
}
[IndexerName("ErrorDictionary")]
public ValidationStatus this[string propertyName]
{
get
{
ValidateAllProperties();
var errors = this.GetErrors()
.ToDictionary(k => k.MemberNames.First(), v => v.ErrorMessage) ?? new Dictionary<string, string?>();
var hasErrors = errors.TryGetValue(propertyName, out var error);
return new ValidationStatus(hasErrors, error ?? string.Empty);
}
}
public void ValidateModel()
{
ValidateAllProperties();
var validationMessages = this.GetErrors()
.ToDictionary(k => k.MemberNames.First().ToLower(), v => v.ErrorMessage);
ValidationCompleted?.Invoke(validationMessages);
}
}
public partial class PlayerModel : BaseViewModel
{
private int id;
private string name;
private string webImageLink;
private string club;
private string birthday;
private string birthPlace;
private int? weight;
private double? height;
private string description;
private PositionModel position;
public int Id
{
get => this.id;
set => SetProperty(ref this.id, value, true);
}
[Required]
[StringLength(255)]
[MinLength(2)]
public string Name
{
get => this.name;
set
{
SetProperty(ref this.name, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Name]");
}
}
[Required]
[StringLength(4096)]
public string WebImageLink
{
get => this.webImageLink;
set
{
SetProperty(ref this.webImageLink, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[WebImageLink]");
}
}
[Required]
[StringLength(255)]
[MinLength(2)]
public string Club
{
get => this.club;
set
{
SetProperty(ref this.club, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Club]");
}
}
[Required]
[StringLength(32)]
public string Birthday
{
get => this.birthday;
set
{
SetProperty(ref this.birthday, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Birthday]");
}
}
[Required]
[StringLength(255)]
public string BirthPlace
{
get => this.birthPlace;
set
{
SetProperty(ref this.birthPlace, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[BirthPlace]");
}
}
[Required]
[Range(0, 100)]
public int? Weight
{
get => this.weight;
set
{
SetProperty(ref this.weight, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Weight]");
}
}
[Required]
[Range(0, 2.5)]
public double? Height
{
get => this.height;
set
{
SetProperty(ref this.height, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Height]");
}
}
[Required]
public string Description
{
get => this.description;
set
{
SetProperty(ref this.description, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Description]");
}
}
[Required]
public PositionModel Position
{
get => this.position;
set
{
SetProperty(ref this.position, value, true);
ClearErrors();
ValidateAllProperties();
OnPropertyChanged("ErrorDictionary[Position]");
}
}
public PlayerModel() : base()
{
}
public PlayerModel(int id, string name, string webImageLink, string club, string birthday, string birthPlace, int weight, double height, string description, string positionName, int positionId) : base()
{
Id = id;
Name = name;
WebImageLink = webImageLink;
Club = club;
Birthday = birthday;
BirthPlace = birthPlace;
Weight = weight;
Height = height;
Description = description;
Position = new PositionModel(positionId, positionName);
}
public PlayerModel(int id, string name, string webImageLink, string club, string birthday, string birthPlace, int weight, double height, string description, PositionModel position) : base()
{
Id = id;
Name = name;
WebImageLink = webImageLink;
Club = club;
Birthday = birthday;
BirthPlace = birthPlace;
Weight = weight;
Height = height;
Description = description;
Position = position;
}
public PlayerModel(PlayerEntity player)
{
Id = player.Id;
Name = player.Name;
WebImageLink = player.WebImageLink;
Club = player.Club;
Birthday = player.Birthday;
BirthPlace = player.BirthPlace;
Weight = player.Weight;
Height = player.Height;
Description = player.Description;
Position = new PositionModel(player.Position);
}
public PlayerEntity ToEntity()
{
return new PlayerEntity
{
Id = Id,
Name = Name,
WebImageLink = WebImageLink,
Club = Club,
Birthday = Birthday,
BirthPlace = BirthPlace,
Weight = Weight.Value,
Height = Height.Value,
Description = Description,
PositionId = Position.Id
};
}
public void ToEntity(PlayerEntity player)
{
player.Id = Id;
player.Name = Name;
player.WebImageLink = WebImageLink;
player.Club = Club;
player.Birthday = Birthday;
player.BirthPlace = BirthPlace;
player.Weight = Weight.Value;
player.Height = Height.Value;
player.Description = Description;
player.PositionId = Position.Id;
}
}
I have a response from the server, the result is 200, there is content in the response, but when the line var result = await JsonSerializer.DeserializeAsync(stream, options); runs, no errors, no exception, no result, the code just stops.
thnx
UPDATE:
So I tried the suggested
ReadAsStringAsync()
ReferenceHandler = ReferenceHandler.IgnoreCycles
none worked.
When I deserialize to string, I got the following json as string:
[{"id":1,"name":"Nikola Radosová","webImageLink":"https://d3t3ozftmdmh3i.cloudfront.net/production/podcast_uploaded_episode/1378584/1378584-1567610413757-54d2f2d5dc6be.jpg","club":"FATUM Nyíregyháza","birthday":"1992.05.03","birthPlace":"Bojnice, Czechoslovakia","weight":66,"height":1.86,"description":"Nikola Radosová (born 3 May 1992) is a Slovak female volleyball player. She is part of the Slovakia women's national volleyball team. She competed at the 2019 Women's European Volleyball Championship.","position":{"id":1,"name":"outside hitter"},"validateCommand":{},"hasErrors":false},{"id":2,"name":"Tanja Matic","webImageLink":"https://brse.hu/wp-content/uploads/2022/07/Tanja-vote.jpg","club":"1. MCM-Diamant","birthday":"1983.03.21","birthPlace":"Subotica, Szerbia","weight":57,"height":1.79,"description":"Tanja Matic több száz szerb élvonalbeli mérkőzéssel a háta mögött, a patinás Szpartak Szabadka korábbi csapatkapitányaként 2015 nyarán érkezett hazánkba, és előbb két éven át játszott Békéscsabán, majd két szezont húzott le Nyíregyházán. A csabaiakkal mindent megnyert, amit csak itthon lehetett: a bajnokságban és a Magyar Kupában is két-két elsőséggel gazdagodott, emellett egy Közép-európai Liga elsőséget is begyűjtött. A nyíregyháziakkal két alkalommal hódította el a Magyar Kupa-trófeát, és 2018-ban, illetve 2019-ben is bejutott a bajnokság döntőjébe, ahol végül ezüstéremmel zárt. A tapasztalt röplabdázó ezek után, pályafutásának újabb állomásaként Kaposvárt választotta, így újra együtt dolgozhatott korábbi edzőjével, Sasa Nedeljkoviccsal. A 2019/2020-as évadban elért eredményekre mindenki büszke lehet, de mivel az ismert okok miatt váratlanul félbeszakadt, majd véget is ért a pontvadászat, mindenki kettőzött erővel szeretne majd újra munkába állni","position":{"id":2,"name":"opposite"},"validateCommand":{},"hasErrors":false}]
UPDATE 2: The method that calls deserialization:
protected async Task<T> SendGetRequestAsync<T>(string route, object routParam)
{
try
{
var uri = BuildUri(route, routParam);
var response = await httpClient.GetAsync(uri);
response.EnsureSuccessStatusCode();
var content = await SerializeResponse<T>(response.Content);
return content;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
UPDATE 3:
I just created a single console app, to find out what is wrong.
I am getting an exception:
System.Text.Json.JsonException: ''S' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.'.
The 'S' is not is, its something like $ sing, but it's not.
You should add JsonSerializerOptions Referance Handler
Here your solution
new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.IgnoreCycles
}
var result = await JsonSerializer.DeserializeAsync<T>(stream, new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.IgnoreCycles
});
forget about a stream
using (var response = await client.PostAsync(api, requestContent))
{
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(responseContent);
}
}
the class you posted is too complicated and I am sure has not seriazible code. So I recommend you to create DTO like this one using online tool for example. This DTO is very short and simple, but it deserializes your json string properly. After this you can try to map DTO data to your classes. Or better you can find a lot code examples, that shows how to use DTO as a base class of the class that implements MVVM pattern
List<DTO> data = JsonConvert.DeserializeObject<List<DTO>>(json);
public partial class DTO
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("webImageLink")]
public Uri WebImageLink { get; set; }
[JsonProperty("club")]
public string Club { get; set; }
[JsonProperty("birthday")]
public string Birthday { get; set; }
[JsonProperty("birthPlace")]
public string BirthPlace { get; set; }
[JsonProperty("weight")]
public long Weight { get; set; }
[JsonProperty("height")]
public double Height { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("position")]
public Position Position { get; set; }
[JsonProperty("validateCommand")]
public ValidateCommand ValidateCommand { get; set; }
[JsonProperty("hasErrors")]
public bool HasErrors { get; set; }
}
public partial class Position
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public partial class ValidateCommand
{
}
Related
The propblem: There is no "Name" field in the object or csv file, yet CsVHelper keeps looking for "Name" in the header. So why is it tripping there and what are some fixes?
When trying to build objects from a csv file, the following error comes up:
CsvHelper.HeaderValidationException: Header with name 'Name' was not found. If you are expecting some headers to be missing and want to ignore this validation, set the configuration HeaderValidated to null. You can also change the functionality to do something else, like logging the issue.
at CsvHelper.Configuration.ConfigurationFunctions.HeaderValidated(Boolean isValid, String[] headerNames, Int32 headerNameIndex, ReadingContext context)
I have tried setting HeaderValidated to null, but got the same results.
The header of the csv:
Id|Title|Description|AssignedToUserId|SourceUserId|DateCreated|DateAssigned|DateCompleted|Notes
The parsing code:
private static IEnumerable<T> GetCSVData<T>(string fullFileName)
{
PrintMembers<T>();
using (var reader = new StreamReader(fullFileName))
{
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.IncludePrivateMembers = false;
csv.Parser.Configuration.Delimiter = "|";
var records = csv.GetRecords<T>().ToList();
return records;
}
}
}
A quick function for listing the public properties and fields of the class (T) being passed in outputs the following:
Properties...
Id
AssignedToUserId
SourceUserId
Title
Description
AssignedTo
Source
DateCreated
DateAssigned
DateCompleted
RelatedTasks
Notes
Fields...
[None]
They all have getters and setters.
EDIT
The IntermediateTask is the generic being fed into GetCSVData(). It has a default constructor. IntermediateTask is internal, but is in the same assembly as GetCSVData().
Code for the class(es) in question:
internal class IntermediateTask : Task
{
private int _Id;
new public int Id
{
get { return _Id; }
set { _Id = value; }
}
private int _AssignedToUserId;
public int AssignedToUserId
{
get { return _AssignedToUserId; }
set
{
_AssignedToUserId = value;
base.AssignedTo = userManager.Get(_AssignedToUserId);
}
}
private int _SourceUserId;
public int SourceUserId
{
get { return _SourceUserId; }
set
{
this._SourceUserId = value;
base.Source = userManager.Get(_SourceUserId);
}
}
public IntermediateTask() : base("", "", new IntermediateUser(), new IntermediateUser())
{
}
}
public class Task
{
public Task(string title, string description, User assignedTo, User source, DateTime? dateCreated = null, int id = 0)
{
this.RelatedTasks = new List<Task>();
this.Title = title;
this.Description = description;
this.AssignedTo = assignedTo;
this.Source = source;
this.DateCreated = dateCreated ?? DateTime.Now;
this.Id = id;
}
private int _Id;
public int Id
{
get { return _Id; }
protected set { _Id = value; }
}
public string Title { get; set; }
public string Description { get; set; }
public User AssignedTo { get; set; }
public User Source { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateAssigned { get; set; }
public DateTime? DateCompleted { get; set; }
public IList<Task> RelatedTasks { get; set; }
public string Notes { get; set; }
override public string ToString()
{
return $"Id: {Id}; Title: {Title}";
}
}
In my case it complained about AssignedTo missing, but that is actually a property in the class that is not in the csv, so I had to add these two lines to make it work:
csv.Configuration.HeaderValidated = null;
csv.Configuration.MissingFieldFound = null;
I don't know why it would come up with 'Name' unless you have something different.
First, i'm a beginning in c#. I'm try to code some game. I don't know how to return enum value as string.
Here my code.
public class CARDS {
public CARDS(int id, int atk, ClassType ctype, string name) {
this.CARD_ID = id;
this.C_TYPE = ctype;
this.ATK = atk;
this.NAME_EN = name;
}
public CARDS() {
this.CARD_ID = -1;
}
public int CARD_ID { get; set; }
public ClassType C_TYPE { get; set; }
public int ATK { get; set; }
public string NAME_EN { get; set; }
public enum ClassType {
Warrior,
Mage,
Archer,
Thief,
Bishop,
Monk,
Guardian,
Destroyer,
Chaser,
Hermit,
Alchemy
}
}
.......
Here I try to do.
public class CardCollection : MonoBehaviour {
private List<CARDS> dbase = new List<CARDS>();
private JsonData cardsdata;
private JsonData card;
void Start() {
cardsdata = JsonMapper.ToObject(File.ReadAllText(Application.dataPath + "/Json/card.json"));
ConstructCardData();
Debug.Log(dbase[1].NAME_EN + " " + dbase[23].NAME_EN);
}
void ConstructCardData() {
card = cardsdata["CARDS"];
for (int i = 0; i < card.Count; i++) {
dbase.Add(new CARDS((int)card[i]["CARD_ID"], (int)card[i]["ATK"], card[i]["C_TYPE"].ToString(), card[i]["NAME_EN"].ToString()));
}
}
}
// card[i]["C_TYPE"].ToString()
It say can't convert from string to CARDS.ClassType
What about :
public class CARDS
{
public CARDS(int id, int atk, ClassType ctype, string name)
{
this.CARD_ID = id;
this.C_TYPE = Enum.GetName(ctype.GetType(), ctype); //Use Enum.GetName to get string
this.ATK = atk;
this.NAME_EN = name;
}
public CARDS()
{
this.CARD_ID = -1;
}
public int CARD_ID { get; set; }
public string C_TYPE { get; set; } //change type to string
public int ATK { get; set; }
public string NAME_EN { get; set; }
public enum ClassType
{
Warrior,
Mage,
Archer,
Thief,
Bishop,
Monk,
Guardian,
Destroyer,
Chaser,
Hermit,
Alchemy
}
}
ToString() on the enum values return the string value of the enum. Custom string values can also be returned for the enum values, check these links, link1 , link2
Examples:
ClassType.Warrior.ToString();
ctype.ToString();
I am trying to get and send a list of this object to a text file. The text file is in the following format.
name,IDnumber,department,value
there are quite a few lines of this so i used a for to read them in.
This is the code for the read and write to the file.
public List<Employee> ReadFile(string fileName) {
StreamReader fileIn = new StreamReader(fileName);
fileIn = File.OpenText(fileName);
List<Employee> list = new List<Employee>();
string[] test;
string name;
string ID;
string dep;
string post;
while (!fileIn.EndOfStream || !File.Exists(fileName)) {
string inString = fileIn.ReadLine();
test = inString.Split('#');
name = test[0];
ID = test[1];
dep = test[2];
post = test[3];
Employee newEmp = new Employee(name, ID, dep, post);
list.Add(newEmp);
}
fileIn.Close();
return list;
}
public void WriteFile(List<Employee> outList, string file) {
StreamWriter writeOut = new StreamWriter(file);
for (int i = 0; i < outList.Count; i++) {
writeOut.WriteLine(outList[i].name + '#' + outList[i].IDnum + '#' + outList[i].department + '#' + outList[i].position);
}
writeOut.close();
}
This is the code for my class. The error is being thrown at the set.
public class Employee {
public string name { get { return name; } set { name = value; } }
public string IDnum { get { return IDnum; } set { IDnum = value; } }
public string department { get { return department; } set { department = value; } }
public string position { get { return position; } set { position = value; } }
public Employee() {
name = string.Empty;
IDnum = string.Empty;
department = string.Empty;
position = string.Empty;
}
public Employee(string newName, string newID) {
name = newName;
IDnum = newID;
department = string.Empty;
position = string.Empty;
}
public Employee(string newName, string newID, string newDep, string
newPost) {
name = newName;
IDnum = newID;
department = newPost;
position = newDep;
}
}
I am not sure if there is some kind of formatting that I am missing for the set function to function as needed. The This is the function i am calling for the in and out of the file. I believe that it is never making it to the out so it is likely how i am importing the data.
It's a really common gotcha... a C# rite of passage!
Let's take a look at a single property (this applies to all of your properties though)...
public string name { get { return name; } set { name = value; } }
so what happens when you try myObj.name = "foo";?
In the set method, you refer back to the very same property name. So it tries to access name, which goes around again (and again, and again, recursively until you StackOverflow).
A backing field with proper naming conventions is the norm here:
private string name;
public string Name{get { return name; } set{ name = value; }}
or even better, if there's no logic involved, an auto-property.
public string Name{ get; set; }
You keep calling IDnum and other properties over and over recursively, until the stack overflows
public string IDnum { get { return IDnum; } set { IDnum = value; } }
When you do something like
IDnum = someValue;
that calls the setter for IDnum, which runs the code in the setter
IDnum = value
Which in turn calls the setter of IDnum, until you run out of stack.
The Fix
In your case, it looks like you can use automatic properties
public string IDnum { get; set; }
You should change
public string name { get { return name; } set { name = value; } }
public string IDnum { get { return IDnum; } set { IDnum = value; } }
public string department { get { return department; } set { department = value; } }
public string position { get { return position; } set { position = value; } }
to
public string name { get; set; }
public string IDnum { get; set; }
public string department { get; set; }
public string position { get; set; }
or introduce backing fields:
private string _name;
public string name { get { return _name; } set { _name = value; } }
See https://msdn.microsoft.com/en-us/library/bb384054.aspx for more info on Auto-Implemented Properties in C#.
Please note, that the commonly used naming of public properties is PascalCasing. Your properties in PascalCasing would look like this:
public string Name { get; set; }
public string IdNum { get; set; }
public string Department { get; set; }
public string Position { get; set; }
I have the following model:
Base class:
public abstract class Identifiable{
private ObjectId id;
private string name;
protected Identifiable(){
id = ObjectId.GenerateNewId();
}
[BsonId]
public ObjectId Id{
get { return id; }
set { id = value; }
}
[BsonRequired]
public string Name{
get { return name; }
set { name = value; }
}
}
The name is unique.
A channel class
public class Channel : Identifiable{
private DateTime creationDate;
private string url;
private DailyPrograming dailyPrograming;
public DailyPrograming DailyPrograming{
get { return dailyPrograming; }
set { dailyPrograming = value; }
}
public DateTime CreationDate{
get { return creationDate; }
set { creationDate = value; }
}
public string Url{
get { return url; }
set { url = value; }
}
}
Daily programs. The name property is the date stored as ddMMyyyy:
public class DailyPrograming : Identifiable{
public DailyPrograming(){
DailyPrograms = new List<Program>(30);
}
public IList<Program> DailyPrograms { get; set; }
}
The programs:
public class Program : Identifiable{
private DateTime programDate;
private string category;
private string description;
public DateTime ProgramDate{
get { return programDate; }
set { programDate = value; }
}
public string Category{
get { return category; }
set { category = value; }
}
public string Description{
get { return description; }
set { description = value; }
}
}
Now, I want to filter the program of certain channel for specific date using:
public DailyPrograming GetProgramsForDate(string channelId, string prgDate){
ObjectId id = new ObjectId(channelId);
IMongoQuery query = Query.And(Query<Channel>.EQ(c => c.Id, id),
Query<DailyPrograming>.EQ(dp => dp.Name, prgDate));
var result = Database.GetCollection<DailyPrograming>(CollectionName).Find(query).FirstOrDefault();
return result;
}
But it never returns the existing data. How to retrieve the programings of a channel for a date?
-
var builder = Builders<BsonDocument>.Filter;
var filt = builder.Eq("Price", "9.20")
& builder.Eq("ProductName", "WH-208");
var list = await collection.Find(filt).ToListAsync();
We can use & instead of $and. See this post, for another example.
According to your sample I used id = "54c00c65c215161c7ce2a77c" and prgDate = "2212015"
then I changed the query to this:
var collection = database.GetCollection<Channel>("test6");
var id = new ObjectId("54c00c65c215161c7ce2a77c");
var query = Query.And(Query<Channel>.EQ(c => c.Id, id), Query<Channel>.EQ(c => c.DailyPrograming.Name, "2212015"));
var result = collection.Find(query).FirstOrDefault();
this query works fine
Some point:
Your collection type is Chanel not DailyPrograming
When your collection is Chanel you have to use Query<Channel> and query nested DailyPrograming via Query<Channel>.EQ(c => c.DailyPrograming.Name, "2212015")
This is the working class:
namespace Lite
{
public class Spec
{
public int ID { get; set; }
public string Name { get; set; }
public string FriendlyName { get; set; }
public int CategoryID { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public string UOM { get; set; }
public int Pagination { get; set; }
public int ColoursFront { get; set; }
public int ColoursBack { get; set; }
public string Material { get; set; }
public int GSM { get; set; }
public string GSMUOM { get; set; }
public bool Seal { get; set; }
public Spec(int ID)
{
using (CrystalCommon.MainContext db = new CrystalCommon.MainContext())
{
var q = (from c in db.tblSpecifications where c.id == ID select c).SingleOrDefault();
if (q != null)
loadByRec(q);
}
}
public Spec(CrystalCommon.tblSpecification Rec)
{
loadByRec(Rec);
}
public void loadByRec(CrystalCommon.tblSpecification Rec)
{
this.ID = Rec.id;
this.Name = Rec.Title;
this.Width = Convert.ToInt32(Rec.FinishedSizeW.Value);
this.Height = Convert.ToInt32(Rec.FinishedSizeL.Value);
this.UOM = Rec.FlatSizeUOM;
this.Pagination = Rec.TxtPagination.Value;
this.ColoursFront = Convert.ToInt32(Rec.TxtColsF.Value);
this.ColoursBack = Convert.ToInt32(Rec.TxtColsB.Value);
this.Material = Rec.TxtMaterial;
this.GSM = Rec.TxtGSM.Value;
this.GSMUOM = Rec.txtGsmUnit;
this.Seal = Rec.TxtSeal.Value == 1;
}
public string displayDimensions()
{
return Width + " x " + Height + " " + UOM;
}
}
}
Then I try and modify the Name getter and setter:
namespace Lite
{
public class Spec
{
public int ID { get; set; }
// User friendly name if available otherwise fall back on spec name
public string Name { get {
if (null != FriendlyName)
return FriendlyName;
else
return Name;
}
set
{
Name = value;
}
}
public string FriendlyName { get; set; }
public int CategoryID { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public string UOM { get; set; }
public int Pagination { get; set; }
public int ColoursFront { get; set; }
public int ColoursBack { get; set; }
public string Material { get; set; }
public int GSM { get; set; }
public string GSMUOM { get; set; }
public bool Seal { get; set; }
public Spec(int ID)
{
using (CrystalCommon.MainContext db = new CrystalCommon.MainContext())
{
var q = (from c in db.tblSpecifications where c.id == ID select c).SingleOrDefault();
if (q != null)
loadByRec(q);
}
}
public Spec(CrystalCommon.tblSpecification Rec)
{
loadByRec(Rec);
}
public void loadByRec(CrystalCommon.tblSpecification Rec)
{
this.ID = Rec.id;
this.Name = Rec.Title;
this.Width = Convert.ToInt32(Rec.FinishedSizeW.Value);
this.Height = Convert.ToInt32(Rec.FinishedSizeL.Value);
this.UOM = Rec.FlatSizeUOM;
this.Pagination = Rec.TxtPagination.Value;
this.ColoursFront = Convert.ToInt32(Rec.TxtColsF.Value);
this.ColoursBack = Convert.ToInt32(Rec.TxtColsB.Value);
this.Material = Rec.TxtMaterial;
this.GSM = Rec.TxtGSM.Value;
this.GSMUOM = Rec.txtGsmUnit;
this.Seal = Rec.TxtSeal.Value == 1;
}
public string displayDimensions()
{
return Width + " x " + Height + " " + UOM;
}
}
}
On my computer this compiles fine, but the server seems to crash when it runs. (First version works fine). My colleague compiled it on his machine and it threw a "Stack overflow error" apparently, but he's not around for me to get specifics on that right now.
Am I applying the getter correctly here?
This is an endless loop:
public string Name { get {
...
set
{
Name = value;
}
}
The setter will call itself repeatedly until you get the Stack overflow exception.
usually you have a backing variable, so it ends up like this
private string name;
public string Name {
get {
if (null != FriendlyName)
return FriendlyName;
else
return name;
}
set {
name = value;
}
}
Your set is referencing the property itself, and your get is referencing the property itself, both of these will cause a potentially endless loop leading to a StackOverflowException (no more stack space to push the current call into). You need to use a backing field:
private string _name;
public string Name
{
get
{
if (null != FriendlyName)
return FriendlyName;
else
return _name;
}
set
{
_name = value;
}
}
It looks as though you tried to turn an auto-property into a manual one. Auto-properties (public string Name { get; set; }) work because the compiler will create the backing field itself.
As a learning exercise, if you step through with the debugger and step into return Name or Name = value you will see first hand the code going back into the property you are already in.
This is much better.
string _name = "";
public string Name
{
get { return FriendlyName ?? _name; }
set { _name = value; }
}
One of your properties gets and sets itself, see:
public string Name
{
get {
if (null != FriendlyName)
return FriendlyName;
else
return Name; //<-- StackOverflow
}
set
{
Name = value; //<-- StackOverflow
}
}
You have a getter for Name, that calls the property Name, which will call the getter for Name, etc. You need a private field to back the property, and you need to access that backing field in your getter instead.
public string Name { get {
if (null != FriendlyName)
return FriendlyName;
else
return Name;
}
set
{
Name = value;
}
}
Name in the get/set refers to the property. You will need to define a backing field and use that.
If FriendlyName is null then the Name getter attempts to get the value from the Name getter - i.e. it loops. This is what causes the stack overflow.
No you should use a backing field. The error is in the else
public string Name { get {
if (null != FriendlyName)
return FriendlyName;
else
return Name;//error, you're calling the property getter again.
}