I have a custom class that gets some data from the web.
When I get this data I want to set it to the value of a property but when I do this unity crashes. The commented line generates the crash without this line everything works fine. See my code below:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class GetDB
{
private readonly Main m;
private readonly string Url;
public string DBData {
get
{
if(DBData == null)
return null;
else
return DBData;
}
private set
{
DBData = value;
}
}
public GetDB(Main m, string url)
{
this.m = m;
this.Url = url;
}
public void GetServerData(){
m.StartCoroutine(GetText(Url, (result) =>{
this.DBData = result; //THIS LINE CRASHES UNITY
Debug.Log(result);
}));
}
IEnumerator GetText(string url, Action<string> result) {
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) {
Debug.Log(www.error);
}
else {
if (result != null)
result(www.downloadHandler.text);
}
}
}
How would I go about fixing this, and what exactly is happening here?
If anything is unclear let me know so I can clarify.
You have to use a backing field for the property:
string _dbData;
public string DBData
{
get
{
if(_dbData == null)
return null;
else
return _dbData;
}
private set
{
_dbData= value;
}
}
A property is just syntactic sugar for a getter and setter methods. So you can rewrite your property like:
public string GetDBData()
{
if(_dbData == null)
return null;
else
return _dbData;
}
public void SetDBData(string value)
{
_dbData = value;
}
The way you have implemented the property:
public void SetDBData(string value)
{
// you will never get out of here
SetDBData(value);
}
Properties act as accessors for variables. What is happening in your case is basically an endless loop - whenever somebody tries to get the value of your property, it keeps returning the property itself. Instead, you want a backing field _dbData:
private string _dbData;
public string DBData
{
get
{
return _dbData;
}
private set
{
_dbData = value;
}
}
Now your property controls the accesss to this field.
Your accessor can be really simplified.
Doing :
get
{
if(DBData == null)
return null;
else
return DBData;
}
Will provide exactly the same result than doing :
get
{
return DBData; //if DBData is null, it will return null
}
So, you can write your accessor that way :
public string DBData
{
get;
private set;
}
Related
I have an object that represents a record of a table in my database, for example 'Project'.
My User class has different properties which are the records of other tables, for example, 'Client' or 'Accountancy'. Those also have properties to related tables.
Each of these properties returns a local value (already loaded) if not null, and there is no loaded information, it generates a request to get this value from database.
My issue is the following : when I set a breakpoint, and check the object in the debug window, it loads automatically all the values of the properties, and so, requests the database.
With this scenario, I cannot have a precise and static snapshot of my object at the moment.
Is there a way, in code, not to go through this part of code if in debug window ?
For instance, something like that:
public MyBaseObject GetProperty<T>(string columnName_, string alias_ = null) where T : MyBaseObject, new()
{
var ret = GetExtract<T>(columnName_, alias_);
// if the data are loaded
if (ret.Id != null)
return ret;
// Fake boolean I would like
if(InDebugWindowAfterAbreakPointForInstance)
return ret;
else
ret = LoadFromDatabase<T>(columnName_, alias_)
return ret;
}
I've found different attributes with the debugger, like the DebuggerStepperBoundaryAttribute, but nothing that could do something like that.
In situations like this the only way I know of is to use a DebuggerTypeProxy for each of your types then in that proxy have it access the backing field directly instead of going through the property that causes the database lookup to happen.
Here is a simple example program.
public class Program
{
public static void Main(string[] args)
{
var client = new Client();
Debugger.Break();
Debugger.Break();
}
}
[DebuggerTypeProxy(typeof(ClientDebugView))]
public class Client : MyBaseObject
{
private string _firstName;
private string _lastName;
public string FirstName
{
get
{
if (_firstName == null)
_firstName = GetProperty<string>("FirstName");
return _firstName;
}
set
{
if (Equals(_firstName, value))
return;
_firstName = value;
UpdateDatabase(_firstName, "FirstName");
}
}
public string LastName
{
get
{
if (_lastName == null)
_lastName = GetProperty<string>("LastName");
return _lastName;
}
set
{
if (Equals(_lastName, value))
return;
_lastName = value;
UpdateDatabase(_lastName, "LastName");
}
}
internal class ClientDebugView : MyBaseObjectDebugView
{
private readonly Client _client;
public ClientDebugView(Client client)
: base(client)
{
_client = client;
}
public string FirstName
{
get { return _client._firstName; }
}
public string LastName
{
get { return _client._lastName; }
}
}
}
[DebuggerTypeProxy(typeof(MyBaseObjectDebugView))]
public class MyBaseObject
{
private Guid? _id;
public Guid? Id
{
get
{
if (_id == null)
_id = GetProperty<Guid?>("Id");
return _id;
}
set
{
if (Equals(_id, value))
return;
_id = value;
UpdateDatabase(_id, "Id");
}
}
//Fake loading data from a database.
protected T GetProperty<T>(string columnName)
{
object ret = null;
switch (columnName)
{
case "Id":
ret = Guid.NewGuid();
break;
case "LastName":
ret = "Smith";
break;
case "FirstName":
ret = "John";
break;
default:
ret = null;
break;
}
return (T)ret;
}
protected void UpdateDatabase<T>(T id, string s)
{
throw new NotImplementedException();
}
internal class MyBaseObjectDebugView
{
private readonly MyBaseObject _baseObject;
public MyBaseObjectDebugView(MyBaseObject baseObject)
{
_baseObject = baseObject;
}
public Guid? Id
{
get { return _baseObject._id; }
}
}
}
If you view the client object in the debugger you will see it leaves the backing fields null between the two breakpoints unless you open the "Raw View" at the first breakpoint.
The nodes have existed.
I tried to add edges by unwind,but my function importBuyConnectionIntoNeo4j didn't work,
Is there any one can help me?
the data structure:
class Connection
{
private string type;
public string Type
{
get { return type; }
set { type = value; }
}
private string source;
public string Source
{
get { return source; }
set { source = value; }
}
private string target;
public string Target
{
get { return target; }
set { target = value; }
}
}
class BuyConnection:Connection
{
}
myFunction:
public void importBuyConnectionIntoNeo4j(List<BuyConnection> connectionList)
{
GraphClient client = createConnectionToNeo4j();
client.Cypher
.Unwind(connectionList, "connection")
.Match("(source:Person),(target:Vegetable)")
.Where("source.Name=connection.Source AND target.Type=connection.Target")
.Create("(source)-[:Buy]->(target)")
.ExecuteWithoutResults();
}
I think the issue is with your .where text:
.Where("source.Name=connection.Source AND target.Type=connection.Target")
is the Source and Target the right way around?
I'm trying to write an "onchange" event for a C# class that I have. The idea would be to capture anytime the class was instantiated or a property was changed and fire off some code to evaluate the "health" of the object, then set a property of the class to true or false based off of the method being invoked. My initial attempts were to simply call a private method in the setter of each property as such:
string _source = null;
public string Source
{
set
{
this._source = value;
OnClassChange();
}
get { return this._source; }
}
string _dest = null;
public string Dest
{
set
{
this._dest = value;
OnClassChange();
}
get { return this._dest; }
}
bool _isValid;
public bool IsValid
{
get { return _isValid; }
}
void OnClassChange()
{
_isValid = (_source == null) ? false : true ;
_isValid = (_dest == null) ? false : true;
}
but this seems sort of clunky and not elegant... I'd like to use some sort of listener, then in my OnClassChange() block simply loop through all the private properties of the class, determine the type of property and invoke some logic to determine if the values of the property is valid or not in a loop.
You don't really need a field for this at all - unless the validation is costly (so you want to avoid recomputing it each time it's requested) you can just have:
public string Source { get; set; }
public string Destination { get; set; }
public bool IsValid { get { return Source != null && Destination != null; } }
In C# 6 the IsValid code would be be even simpler:
public bool IsValid => Source != null && Destination != null;
I have a class that is used for storing user data to a file. It works well, but can't really be placed into a PCL library easily. Outside of the PCL, it's all fine.
The class looks like this
public static class UserData
{
public static object GetPropertyValue(this object data, string propertyName)
{
return data.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(data, null);
}
public static object SetPropertyValue<T>(this object data, string propertyName, T value)
{
data.GetType().GetProperties().Single(pi => pi.Name == propertyName).SetValue(data, value);
return new object();
}
private static string pUserSettingsFile;
private static UserSettings userSetting;
public static bool AccountEnabled
{
get
{
return UserSettings.account_enabled;
}
set
{
UserSettings settings = UserSettings;
settings.account_enabled = value;
UserSettings = settings;
}
}
public static UserSettings UserSettings
{
get
{
if (userSetting == null)
{
if (File.Exists(UserSettingsFile))
{
userSetting = Serializer.XmlDeserializeObject<UserSettings>(UserSettingsFile);
}
else
{
userSetting = new UserSettings();
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
return userSetting;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value is null!");
}
userSetting = value;
if (File.Exists(UserSettingsFile))
{
File.Delete(UserSettingsFile);
}
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
public static string UserSettingsFile
{
get
{
if (string.IsNullOrEmpty(pUserSettingsFile))
{
pUserSettingsFile = Path.Combine(GroupShootDroid.Singleton.ContentDirectory, "UserSettings.xml");
}
return pUserSettingsFile;
}
}
#endregion
}
public class UserSettings
{
public bool account_enabled { get; set; }
public string address { get; set; }
public string country { get; set; }
}
It's not rocket science, but does what I need it to do.
What I'm trying to do is use the Get/SetPropertyValue methods to return or set any of the properties within the class.
Currently, to access the Get/SetPropertyValue methods I'm using this
public string GetStringValue(string valToGet)
{
string rv = (string)UserData.GetPropertyValue(valToGet);
return rv;
}
public void SetStringValue(string name, string val)
{
UserData.SetPropertyValue(name, val);
}
On compiling though, the GetPropertyValue method is giving an error that No overload for method GetPropertyValue takes 1 argument with the SetPropertyValue complaining that there isn't an overload that takes 2
I'm not sure that the code I'm using will do what I need it to do (from what I've read on here it should be), but I'm more perplexed as to why the errors are showing.
Is there a better way to do what I'm trying to do? The application is a Xam.Forms app, so the PCL accesses the class through an interface using injection.
You are defining extension method, you need an instance of the class to call them:
var o = new Object();
string rv = (string)o.GetPropertyValue(valToGet);
// or, but no sure
string rv = (string)UserData.GetPropertyValue(o, valToGet);
or more probably in your case:
public string GetStringValue(string valToGet)
{
string rv = (string)this.GetPropertyValue(this, valToGet);
//or
//string rv = (string)UserData.GetPropertyValue(this, valToGet);
return rv;
}
I think you're getting confused between the UserData class and the object class. Your extension methods extend object.
I'm trying to send an object of a custom class through my asmx webservice running on .net 4.0, but all i get is an empty response. See below:
<soap:Body>
<ActivateResponse xmlns="http://tempuri.org/">
<ActivateResult /> <!-- why is this empty -->
</ActivateResponse>
</soap:Body>
However, if i modify my method and change the return type for example from class A to B, then it returns all the properties of object B correctly. See below:
<ActivateResponse xmlns="http://tempuri.org/">
<ActivateResult>
<BtAddress>string</BtAddress>
<Name>string</Name>
<Number>string</Number>
</ActivateResult>
</ActivateResponse>
I'm wondering why its happening? I could blame to improper Serialization of class A but there's nothing fancy I'm involving in my class files. Both class files are almost similar in terms of contents and does not contain any Serialize attribute.
So, why does the webservice return one type, but not the other?
Class A:
public class A
{
private string code;
private bool isValid;
private int maxUniqueActivations;
private DateTime dateAdded;
private Customer customer = null;
private bool _initAsEmpty = false;
public License()
{
_initAsEmpty = true;
}
public string LicenseCode
{
get { return code; }
//set { code = String.IsNullOrWhiteSpace(value)? null : value.Trim(); }
}
//If i change return type to Customer, it works too
//so i dont think it should be blamed
public Customer Customer
{
get { return customer; }
}
public bool IsValid
{
get { return isValid; }
}
public int MaxUniqueActivations
{
get { return maxUniqueActivations; }
}
public DateTime DateAdded
{
get { return dateAdded; }
}
}
Class B:
public class Phone
{
private string btAddress, name, number;
private bool isValid;
private DateTime dateAdded;
private bool _initAsEmtpy = false;
public Phone()
{
_initAsEmtpy = true;
}
public string BtAddress
{
get { return btAddress; }
set { btAddress = string.IsNullOrWhiteSpace(value) ? null : value.Replace(":", "").Trim(); }
}
public string Name
{
get { return name; }
set { name = string.IsNullOrWhiteSpace(value) ? null : value.Trim(); }
}
public string Number
{
get { return number; }
set { number = string.IsNullOrWhiteSpace(value) ? null : value.Trim(); }
}
public bool IsValid
{
get { return isValid; }
}
public DateTime DateAdded
{
get { return dateAdded; }
}
}
some methods are suppressed
In order to be serializable, a class must have public setters on its properties. That's the difference between classes A and B, and the reason why A won't serialize.
Probably :)
I think the problem may be with the Customer class. Maybe it is private or something. Try checking it out.