I have an object like this:
public class CustomObject{
public byte[] FieldA {private get; set;}
public IPAddreess FieldB {private get; set;}
}
FieldA is the byte rappresentation of FieldB.
I create this object from two sources of data.
One from a binary file where i need to be fast, then i prefer to set only the FieldA. The other one is in an application where i retrieve the data only in "FieldB format".
I want a function like this:
public IPAddress GetField(){
if (FieldB != null)
return FieldB;
FieldB = new IPAddress(FieldA);
return FieldB;
}
To simplify i used an IPAddress conversion, but usually i have more complex operations to do.
Is this the correct way to do this? Or there is some other method that can simplify this one? I'm using .NET CORE Thank you in advance
You can do that in FieldB's getter, without explicitly writing a get-method:
private IPAddreess _fieldB;
public IPAddreess FieldB
{
get
{
if (_fieldB == null)
{
_fieldB = new IPAddress(FieldA);
}
return _fieldB;
}
set
{
_fieldB = value;
}
}
This code uses a private backing field _fieldB for storing the property's value. Upon retrieving the property, it'll either return the value already stored in the field, or assign it based on FieldA's contents and then return it.
Related
Following on from my earlier question: c-sharp-convert-existing-class-to-use-properties-correctly
I have a class like this:
public class TestCaseInfo
{
public string text { get; set; } = "";
public string requirement_ref { get; set; } = "";
public string given { get; set; } = "";
public string when { get; set; } = "";
public string then { get; set; } = "";
public UInt32 timeLimit { get; set; } = 0;
}
I was previously populating the structure like this:
if (!getNodeValue(testcase_node.SelectSingleNode("text"), ref testcaseInfo.text))
errStr += nodeError(testcase_node, "Missing 'text' node");
Note: that I am trying to pass it by reference. I have read a load of quetions that all basically say that you can't do this. Fair enough...
So I want to pass in the "real" value (I think its called the backing value?) instead. Something like:
if (!getNodeValue(testcase_node.SelectSingleNode("text"), ref testcaseInfo._text)) // where '_text' should be the 'backing' value.
errStr += nodeError(testcase_node, "Missing 'text' node");
But I am missing two things (probably more!):
What is the backing value called?
I assume its private? - can I make it protected and make it a friend class? (that might be C++ talk... not sure if there is the same idea in C#)?
There is no valid identifier for the backing field for that property. You could not use an auto property, and instead explicitly define the get and set methods of the property, along with your own backing field, thus giving you a valid identifier for the backing field, although it would be very poor design to expose this backing field externally.
What you should do is re-design your code such that you don't need to pass the value by reference in the first place. You should just be passing the string by value and, if the result of this function is the computation of a string, returning it. The caller can then set that string back to the property if that's what they want. That would be the more idiomatic design. (Since you also have a boolean value you'd need to pass both the string and the boolean out, of course.)
As far as you are concerned, your properties may as well not have backing fields. The backing field isn't called anything you can refer to if you didn't explicitly declare it:
private string _name;
public String Name { get { return _name; } set { _name = value; } }
If you write properties with explicit backing fields, as above, you can pass them by ref into a method.
private int _id;
public String ID { get { return int _id; } set { int _id = value; } }
public void Test()
{
Int32.TryParse("Sausage Factory", out _id);
}
I try save complex class inside another class. TypeMask contained inside Entity. TypeMask overloads ToString method, and when time to save Entity comes, a want automaticaly save Mask prop in string form, and when I need load Entity class back automaticaly convert this string to TypeMask(constructor of TypeMask can build TypeMask using string). So what have I overload or from what have I inherit to make it real?
public class Entity
{
[Key]
public int Id { get; set; }
public TypeMask Mask { get; private set; }
}
Here's a way to do this:
public class Entity
{
private TypeMask _typeMask;
[Key]
public int Id { get; set; }
public string TypeMaskString { get; set; }
[NotMapped]
public TypeMask Mask
{
get
{
if (this._typeMask == null && !string.IsNullOrEmpty(TypeMaskString))
{
this._typeMaks = new TypeMask(this.TypeMaskString);
// Or some other way to create a TypeMask from string.
}
return this._typeMask;
}
set
{
this._typeMask = value;
this.TypeMaskString = value.ToString();
}
}
}
There are some things to keep in mind here. When your code makes modifications to a TypeMask object you have to set the object again to update TypeMaskString. Of course, this is error-prone and elaborate, so you want to make sure that TypeMask can be modified through only one method (maybe a method in Entity).
The alternative is to have a property like this (skipping null checks for brevity)
public string TypeMaskString
{
get
{
return this.TypeMask.ToString();
}
set
{
this.TypeMask = new TypeMask(this.TypeMaskString);
}
}
Now the TypeMask object can be modified and TypeMaskString will always return an up-to-date value. But this may hit performance because it potentially converts TypeMask to and from string many times. More often than you may suspect, because EF's change tracker will always read TypeMaskString when it executes DetectChanges, which is a process that runs repeatedly.
I'm using EF4.3 so I'm referring to entities, however it could apply to any class containing properties.
I'm trying to figure out if its possible to compare 2 entities. Each entity has properties that are assigned values for clarity let say the entity is 'Customer'.
public partial class Customer
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
...
...
}
The customer visits my website and types in some details 'TypedCustomer'. I check this against the database and if some of the data matches, I return a record from the database 'StoredCustomer'.
So at this point I've identified that its the same customer returning but I wan't to valid the rest of the data. I could check each property one by one, but there are a fair few to check. Is it possible to make this comparison at a higher level which takes into account the current values of each?
if(TypedCustomer == StoredCustomer)
{
.... do something
}
If you're storing these things in the database, it is logical to assume you'd also have a primary key called something like Id.
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
...
...
}
Then all you do is:
if(TypedCustomer.Id == StoredCustomer.Id)
{
}
UPDATE:
In my project, I have a comparer for these circumstances:
public sealed class POCOComparer<TPOCO> : IEqualityComparer<TPOCO> where TPOCO : class
{
public bool Equals(TPOCO poco1, TPOCO poco2)
{
if (poco1 != null && poco2 != null)
{
bool areSame = true;
foreach(var property in typeof(TPOCO).GetPublicProperties())
{
object v1 = property.GetValue(poco1, null);
object v2 = property.GetValue(poco2, null);
if (!object.Equals(v1, v2))
{
areSame = false;
break;
}
});
return areSame;
}
return poco1 == poco2;
} // eo Equals
public int GetHashCode(TPOCO poco)
{
int hash = 0;
foreach(var property in typeof(TPOCO).GetPublicProperties())
{
object val = property.GetValue(poco, null);
hash += (val == null ? 0 : val.GetHashCode());
});
return hash;
} // eo GetHashCode
} // eo class POCOComparer
Uses an extension method:
public static partial class TypeExtensionMethods
{
public static PropertyInfo[] GetPublicProperties(this Type self)
{
self.ThrowIfDefault("self");
return self.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where((property) => property.GetIndexParameters().Length == 0 && property.CanRead && property.CanWrite).ToArray();
} // eo GetPublicProperties
} // eo class TypeExtensionMethods
Most simple seems to use reflexion : get the properties and/or fields you want to compare, and loop through them to compare your two objects.
This will be done with getType(Customer).getProperties and getType(Customer).getFields, then using getValue on each field/property and comparing.
You might want to add custom informations to your fields/properties to define the ones that needs
comparing. This could be done by defining a AttributeUsageAttribute, that would inherit from FlagsAttribute for instance. You'll then have to retrieve and handle those attributes in your isEqualTo method.
I don't think there's much of a purpose to checking the entire object in this scenario - they'd have to type every property in perfectly exactly as they did before, and a simple "do they match" doesn't really tell you a lot. But assuming that's what you want, I can see a few ways of doing this:
1) Just bite the bullet and compare each field. You can do this by overriding the bool Equals method, or IEquatable<T>.Equals, or just with a custom method.
2) Reflection, looping through the properties - simple if your properties are simple data fields, but more complex if you've got complex types to worry about.
foreach (var prop in typeof(Customer).GetProperties()) {
// needs better property and value validation
bool propertyMatches = prop.GetValue(cust1, null)
.Equals(prop.GetValue(cust2, null));
}
3) Serialization - serialize both objects to XML or JSON, and compare the strings.
// JSON.NET
string s1 = JsonConvert.SerializeObject(cust1);
string s2 = JsonConvert.SerializeObject(cust2);
bool match = s1 == s2;
I have an object class TimeDuration. When I tried to change the value of object taken from the array Span, the value inside the array also changes. How can I get copy of an object that won't change its parent object value? I need to pass this copy to another function where I have to make changes to this object
public void test()
{
List<TimeDuration> Span = new List<TimeDuration>();
TimeDuration ob = new TimeDuration();
ob.FromTime = DateTime.Now;
ob.ToTime = DateTime.Now.AddDays(1);
Span.Add(ob);
//Trying to assign value here!
TimeDuration ob2= Span[1];
ob2.FromTime = DateTime.Now.AddDays(3);
}
public class TimeDuration
{
public DateTime FromTime { get; set; }
public DateTime ToTime { get; set; }
}
Firstly, you should understand why the current code behaves as it does. See my article on reference types and value types for more details.
How can I get copy of an object that won't change its parent object value?
Two simple options:
Create some sort of cloning method which creates a copy of the existing object. You need to do this explicitly - although you could use object.MemberwiseClone as a shortcut in some cases. In many cases it's pretty simple, although inheritance makes it harder.
Make your TimeDuration class immutable, e.g. with methods of WithToTime returning
a new version:
public TimeDuration WithFromTime(DateTime newFromTime)
{
return new TimeDuration(newFromTime, ToTime);
}
You'd make your properties read-only, and provide a constructor taking both values (which can also validate them). You might even consider making it a struct at this point.
Consider turning the class into a struct, and of course also make it immutable:
public struct TimeDuration
{
public DateTime FromTime { get; private set; }
public DateTime ToTime { get; private set; }
public TimeDuration(DateTime fromTime, DateTime toTime) : this()
{
FromTime = fromTime;
ToTime = toTime;
}
public TimeDuration SetFromTime(DateTime fromTime)
{
var copy = this;
copy.FromTime = fromTime;
return copy;
}
public TimeDuration SetToTime(DateTime toTime)
{
var copy = this;
copy.ToTime = toTime;
return copy;
}
}
Make your TimeDuration a struct instead of a class: value types are passed by value, so you will get a kind of "copy" behaviour.
Classes are reference types. The value inside the array is a pointer to the memory location of your TimeDuration object and not a new instance of it. Therefore when you change the value it affects the array also.
You will have to create a new object of TimeDuration and pass that about.
If you're always using TimeDuration this way, you may want to consider changing it from a class to a struct. To duplicate a class, you should implement ICloneable and call the Clone method.
I have simple scenario where I have AnotherTest value based on Test value. This works fine most of the time so that whenever I provide Test I am sure to get AnotherTest easily.
public sealed class Transaction {
public string Test { get;set; }
public string AnotherTest{
get {
int indexLiteryS = Test.IndexOf("S");
return Test.Substring(indexLiteryS, 4);
}
}
}
However I wanted to be able to also set AnotherTest value and be able to read it without having to provide Test value. Is this possible? So kinda 2 types of get based which way it was set. I know I could create 3rdTest but I have some methods that use AnotherTest and other fields and I would have to write overloads of that methods.
Edit:
I read some file supplied by bank. I cut it in pieces put some stuff in Test value and every other field (AnotherTest and similar) of the Transaction gets filled automatically.
However later on I would like to read Transaction from SQL that is already in nice format so I don't need to provide Test to get the rest of the fields. I would like to set those fields with set and then be able to use get without setting Test value.
Yes, like so:
public string Test { get; set; }
public string AnotherTest
{
get
{
if(_anotherTest != null || Test == null)
return _anotherTest;
int indexLiteryS = Test.IndexOf("S")
return Test.Substring(indexLiteryS, 4);
}
set { _anotherTest = value; }
}
private string _anotherTest;
That getter could also be expressed as
return (_anotherTest != null || Test == null)
? _anotherTest
: Test.Substring(Test.IndexOf("S"), 4);
I think this would do what you want it to do:
public sealed class Transaction {
public string Test { get;set; }
public string AnotherTest{
get {
if (_anotherTest != null)
{
return _anotherTest;
}
else
{
int indexLiteryS = Test.IndexOf("S");
return Test.Substring(indexLiteryS, 4);
}
}
set {
_anotherTest = value;
}
}
private string _anotherTest = null;
}
I would suggest turning the problem over.
It sounds like you're dealing with a big field and subfields within it. Instead, how about promoting those subfields to fields and constructing/deconstructing the big field when it's accessed.