Is order of properties in a class important? - c#

I have the following class:
class Foo
{
public Foo()
{
Console.WriteLine("Foo");
}
public string A { get; set; } = GetStr("A");
public string B { get; set; } = GetStr("B");
public static string GetStr(string str)
{
Console.WriteLine(str);
return str;
}
}
when I create an instance from it, the output is this:
A
B
Foo
if I change the of my properties to:
public string B { get; set; } = GetStr("B");
public string A { get; set; } = GetStr("A");
the output is:
B
A
Foo
My Question is:
Does order of properties in a class important and may effect my program?
Note: I use C# 6.0 new feature: Property initializer More

Field (and property, since C# 6) initializers are run first, in the order in which they are declared, then the constructor is executed.
So yes, the order of the properties affects the order in which they will be initialized; but the constructor will always be executed last.

In my experience (in C#), when using reflection, the order of the fields is returned as they are listed in the class (so it may be important).
For example:
public class TestClass
{
// purposely not in alphabetical order and of different types.
public string C { get; set; }
public int A { get; set; }
public string B { get; set; }
}
and then create an instance and assign values:
TestClass testObject = new TestClass();
// purposely not in same order as in class
testObject.B = "1";
testObject.C = "2";
testObject.A = 3;
and finally loop through properties:
foreach (PropertyInfo prop in typeof(TestClass).GetProperties())
{
Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(testObject, null));
}
prints out the following:
C = 2
A = 3
B = 1
The result is the same order as in the class definition.

Order of properties doesn't matter. Your constructor call the GetStr method which writes the string in console. Because of that order of properties seem change.

Related

Initializing property value in one class using the return value of a method in a different class

I have the following structure:
public class LogicStatement : ILogicStatement
{
public string TestLogic { get; set; }
public string CompareLogic { get; set; }
public string Operator { get; set; }
public string Expression();
public bool Value();
}
public class Test : ITest
{
public int TestId { get; set; }
public int LiteralId { get; set; }
public string TestName { get; set; }
public string TestText { get; set; }
public string TestDisplayName { get; }
**public ILogicStatement LogicStatement { get; set; }**
public string Expression { get; set; }
public bool Value { get; set; }
}
public class Literal : ILiteral
{
some property members...
**public List<ITest> Tests {get; set;}**
some method members...
}
Note that the class Test has a member of type LogicStatement, and the class Literal has a member of type List.
Note also that all classes have properties and methods that share the same name: Expression, Value, Expression(), Value().
The value of Expression and Value (properties and methods) depend on values in the LogicStatement class.
Throughout the whole project, I use the Interface Type for to instantiate each object to adhere with Dependency Inversion. To support this, I use a factory-like design to create new instances of Test and LogicStatement.
Example:
public static class Factory
{
public static ILogicStatement CreateLogicStatement()
{
return new LogicStatement();
}
public static ITest CreateTest()
{
return new Test(CreateLogicStatement());
}
public static List<ITest> CreateTests()
{
return new List<ITest>();
}
//repeat the same for evey other class.
}
My goal is to have Expression() and Value() be calculated only once in the bottom level class (LogicStatement), and somehow get transfered to their counterpart properties in the higher level classes.
I'm getting the data from Dapper and it looks like all the nested objects are returned from the Dapper module correctly with the same nested structure I intended, and with the right values for all of their members. All of them but Expression, Expression(), Value, Value() are null.
my constructors look like this:
public LogicStatement()
{
Expression();
Value();
}
public Test(ILogicStatement logicStatement)
{
_logicStatement = logicStatement;
Expression = _logicStatement.Expression();
Value = _logicStatement.Value();
}
public Literal(ITest test)
{
_test = test;
Expression = _test.Expression;
Value = _test.Value;
}
and my main:
List<ILiteral> literals = Factory.CreateLiterals();
List<ITest> tests = Facotry.CreateTests();
List<ILogicStatement> logicStatements = Factory.CreateLogicStatements();
literals = GetDataFromDapper();
This last line seems to assign correct values to all other members on all hierarchies. But I cannot get Expression and Value to be anything other than null.
If I test LogicStatement.Expression() and LogicStatement.Value() standalone, they do return the expexted values. but starting at the first parent class Test, these properties are all null.
I think I'm doing something wrong in the way i'm instantiating my objects. Primarily because I'm not sure i understand basic best practices to write constructors.
Maybe I the desired behavior should be implemented through events, where the Test and Literal classes subscribe to changes in the Expression() and Value() methods (or rather to what calculates them). But I never used events and I'd like to know if this fundamentally can be acheived without them first.
My question: How do I make the Expression() Value() at the bottom level class "Fire up" whenever LogicStatement is instantiated, and then have the Expression and Value properties be assigned accordingly as a result.
In other words, I want the following to always be true:
test[i].Expression == literal[i].Expression == LogicStatement[i].Expression()
I'm a beginner in OOP. So any fundamental explanation is welcome.
As you are new to object oriented programming I would start with the basics and leave factories and adhering with Dependency Inversion and the interfaces away for later.
You could tell Dapper to split joined tables into multiple entities (see https://www.learndapper.com/relationships), but for learning OOP I would start doing everything manually.
Your class design does not look proper to me yet. Not sure what Expression and Value of the LogicStatement are, but if they are calculations based on the other properties, I would implement them as (just to show off with complicated words) lazy initialized cached getter properties that are invalidated in the setters of the relevant properties. That ensures you only calculate them once for as many reads you like but recalculate them on first read after one or multiple properties have been updated.
public class LogicStatement {
private string _testLogic;
private string _compareLogic;
private string _operator;
private string? _expression;
private bool? _value;
public LogicStatement(string testLogic, string compareLogic, string #operator) {
_testLogic = testLogic;
_compareLogic = compareLogic;
_operator = #operator;
}
public string TestLogic {
get {
return _testLogic;
}
set {
_testLogic = value;
InvalidateCachedValues();
}
}
public string CompareLogic {
get {
return _compareLogic;
}
set {
_compareLogic = value;
InvalidateCachedValues();
}
}
public string Operator {
get {
return _operator;
}
set {
_operator = value;
InvalidateCachedValues();
}
}
public string Expression {
get {
string? result = _expression;
if (result is null) {
_expression = result = BuildExpression();
}
return result;
}
}
public bool Value {
get {
bool? result = _value;
if (result is null) {
_value = result = EvaluateValue();
}
return result.Value;
}
}
private void InvalidateCachedValues() {
_expression = null;
_value = null;
}
private string BuildExpression() {
//Your logic goes here
throw new NotImplementedException();
}
private bool EvaluateValue() {
//Your logic goes here
throw new NotImplementedException();
}
}
Sorry, it got a bit bigger with the full properties.
In the other classes I would not copy the Value and the Expression but simply remove these properties as anybody can easily access them through the LogicStatement property:
public class Test {
public Test(int testId, int literalId, string testName, string testText, string testDisplayName, LogicStatement logicStatement) {
TestId = testId;
LiteralId = literalId;
TestText = testText;
TestDisplayName = testDisplayName;
LogicStatement = logicStatement;
}
public int TestId { get; }
public int LiteralId { get; }
public string TestName { get; }
public string TestText { get; }
public string TestDisplayName { get; }
public LogicStatement LogicStatement { get; }
}
and the Literal could look like this (I got a bit confused whether this class has one Test or a list of them, I stick to your constructor + properties that hint in the direction of a single one):
public class Literal {
private Test _test;
public Literal(string property1, int property2, Test test) {
Property1 = property1;
Property2 = property2;
_test = test;
}
public string Property1 { get; }
public int Property2 { get; }
public string Expression => _test.LogicStatement.Expression;
public bool Value => _test.LogicStatement.Value;
}
As you decided not to expose the Test in the Literal it makes sense to provide Expression and Value, otherwise they could also be removed (or kept for convenience).

Can I set SetsRequiredMembers or another attribute for only one member in C# 11?

Consider the following code:
public record Foo
{
public required string A { get; init; }
public required string B { get; init; }
}
public record Bar : Foo
{
public Bar()
{
A = "TEST";
}
}
var bar = new Bar
{
B = "ANOTHER TEST"
}
In this situation the compiler will say that field A is not set, while it is clearly set it just does not know about it. Is there any workaround for this?
No, at the moment there is no way to set it for a specific member. If Foo is external dependency you can workaround by adding ctor parameter for B and using SetsRequiredMembersAttribute:
public record Bar : Foo
{
[SetsRequiredMembers]
public Bar(string b)
{
A = "TEST";
B = b;
}
}
var bar = new Bar("");
But use it with caution - it does not actually check if the ctor does what it claims to, i.e. adding new required member to Foo will not trigger an error.
Demo
Created an API proposal for attribute allowing to specify initialized members.
Not directly an answer, but a workaround that seems to work fine:
public record Foo(string A)
{
public required string B { get; init; }
}
public record Bar : Foo("TEST")
{
}
Sure you can set required only one member if needed.
public record Foo
{
public string A { get; init; }
public required string B { get; init; }
}
public record Bar : Foo
{
public Bar()
{
A = "TEST";
}
}
var bar = new Bar
{
B = "ANOTHER TEST"
};

Copying base class in derived class constructor

Is there a way to copy an object fields to a base class in a derived class constructor without having to individually copying every field?
Example:
public class A
{
int prop1 { get; set; }
int prop2 { get; set; }
}
public class B : A
{
public B(A a)
{
//base = a; doesn't work.
base.prop1 = a.prop1;
base.prop2 = a.prop2;
}
}
A a = new A();
B b = new B(a);
public class A
{
public A(A a)
{
prop1 = a.prop1;
prop2 = a.prop2;
}
int prop1 { get; set; }
int prop2 { get; set; }
}
public class B : A
{
public B(A a) : base (a)
{
}
}
A a = new A();
B b = new B(a);
Something like this, although I'm not sure if it is syntactically correct because I didn't compile it. You should use the base keyword after the child class's constructor to pass the values of it's dependencies to the base class.
Edit: But I just realized that you are passing a base class to a child class. And this is a design flaw.
It sounds like you want to add all properties from A to B without having to specify them all separately. If you don't want to have to keep adding new ones to the constructor, you could use reflection to do the work for you.
public B(A a)
{
var bType = this.GetType();
// specify that we're only interested in public properties
var aProps = a.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
// iterate through all the public properties in A
foreach (var prop in aProps)
{
// for each A property, set the same B property to its value
bType.GetProperty(prop.Name).SetValue(this, prop.GetValue(a));
}
}
A few notes about this:
The above code sets public instance properties, so you'd need to change your properties in A to be public.
I'd only consider this safe because you know that B contains everything in A (since it is derived from it).
If you only have a few properties, especially if they don't change often, just list them individually... it'll be easier to see exactly what your code is doing.
I can't for the life of me understand why you want to do this
You are passing an instance of Base class into the constructor of a derived class. What are you trying to do?
have you tried this = a instead of base = a?
The members are private, so you can't access them from even a derived class. Even if they were protected, you still couldn't access them on an instance of A from the B class.
In order to do this without reflection, the members will have to be public:
public class A
{
public int prop1 { get; set; }
public int prop2 { get; set; }
}
// Define other methods and classes here
public class B : A
{
public B(A a)
{
//base = a; doesn't work.
base.prop1 = a.prop1;
base.prop2 = a.prop2;
}
}
If you really want to do this and cannot access the properties via inheritance then you can do via reflection like this:
public class Aclass
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
public class Bclass : Aclass
{
public Bclass(Aclass aInstance)
{
CopyPropertiesFromAltInstance(aInstance);
}
public void CopyPropertiesFromAltInstance(Aclass aInstance)
{
PropertyInfo[] aProperties = aInstance.GetType().GetProperties();
PropertyInfo[] myProperties = this.GetType().GetProperties();
foreach (PropertyInfo aProperty in aProperties)
{
foreach (PropertyInfo myProperty in myProperties)
{
if (myProperty.Name == aProperty.Name && myProperty.PropertyType == aProperty.PropertyType)
{
myProperty.SetValue(this, aProperty.GetValue(aInstance));
}
}
}
}
}

Generic class check which properties were initialized

Is there a way how I can check from an instantiated class which properties were initially set?
As you can see in the example I can check for "null" value of string data type but I can't check for int value since default value is "0".
Is there a way how I can check if a property was set at "instantiation-time" of the object?
I would like to be able to pass any class to the "ParseProperties" class.
Check this example:
class Program
{
static void Main(string[] args)
{
// The following foreach gives me the output as follows
// Actual output:
// Id
// Name
// Age
//
// Desired output:
// John
foreach (string initiatedPropery in ParseProperties(new Person { Name = "John" }))
{
Console.WriteLine(initiatedPropery);
}
// The following foreach gives me the output as follows
// Actual output:
// Id
// Age
//
// Desired output:
// Id
foreach (string initiatedPropery in ParseProperties(new Person { Id = 45 }))
{
Console.WriteLine(initiatedPropery);
}
Console.ReadLine();
}
private static List<string> ParseProperties<T>(T obj)
{
var initiatedProperties = new List<string>();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
// For strings I can check if property is null but I can't check for int's if they were set. How could I do that?
var value = typeof(T).GetProperty(property.Name).GetValue(obj, null);
if (value != null) // --> I would need to get somehow if a property was initially set or not
{
initiatedProperties.Add(property.Name);
}
}
return initiatedProperties;
}
private class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
Given a class like this:
private class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
There is really no way to handle this in general that doesn't involve some changes to the class itself. The best you could do without changing the class you are using as the generic type parameter would be something like comparing to myProp == default(S), where S is the type of the property. This would tell you that the property might not have be initialized.
If you can change the classes that are being passed as generic parameters, then you have a lot more options. The simplest would be:
public int? Age { get; set; }
Now the Age property will be null rather than 0.
Another strategy would be to have another property that will tell you if Age was set:
public bool AgeWasSet { get; private set; }
private int _age;
public int Age
{
get { return _age; }
set { _age = value; AgeWasSet = true; }
}
And you could use some convention like propNameWasSet as a property to identify which property is related to which (this isn't unheard of, JSON.Net for example will look for properties with the name ShouldSerializepropName as a way to inject some logic into serialization).
Finally, you could do something like have a base class or an interface that defines a method to give you the information you need. Something like:
public interface IFieldInitializationInfo
{
string[] GetUninitializedFields(); // or maybe PropertyInfo[]
}
And then your classes can implement that interface and report what fields haven't be initialized according to whatever logic you want to use for that particular class.
Is there a way how I can check if a property was set at "instantiation-time" of the object?
Disregarding the use of int? versus int for a "uninitialized" integer, there is no way to tell if values were set in an initializer. An initializer is the equivalent of setting the properties after construction, so
Person p = new Person() {Id = 4};
is exactly the same as
Person p = new Person();
p.Id = 4;
If you require certain properties to be set when the object is constructed, then use a constructor:
public Person(int id)
{
Id = id;
}

Best practice for protobuf-net, versioning and surrogate types

I'm trying to determine how to address this use case using protobuf-net (Marc Gravell's implementation).
We have class A, which is considered version 1
An instance of class A has been serialized to disk
We now have class B, which is considered version 2 of class A (there were so many things wrong with class A, we had to create class B for the next version). Class A still exists in code, but only for legacy purposes.
I want to deserialize the version:1 data (stored to disk) as a class B instance, and use a logic routine to translate the data from the previous class A instance to a new instance of class B.
The instance of class B will be serialized to disk during operation.
The application should expect to deserialize instances of both class A and B.
The concept of data contract surrogates and the DataContractSerializer come to mind. The goal is transition the version:1 data to the new class B structure.
An example:
[DataContract]
public class A {
public A(){}
[DataMember]
public bool IsActive {get;set;]
[DataMember]
public int VersionNumber {
get { return 1; }
set { }
}
[DataMember]
public int TimeInSeconds {get;set;}
[DataMember]
public string Name {get;set;}
[DataMember]
public CustomObject CustomObj {get;set;} //Also a DataContract
[DataMember]
public List<ComplexThing> ComplexThings {get;set;} //Also a DataContract
...
}
[DataContract]
public class B {
public B(A a) {
this.Enabled = a.IsActive; //Property now has a different name
this.TimeInMilliseconds = a.TimeInSeconds * 1000; //Property requires math for correctness
this.Name = a.Name;
this.CustomObject2 = new CustomObject2(a.CustomObj); //Reference objects change, too
this.ComplexThings = new List<ComplexThings>();
this.ComplexThings.AddRange(a.ComplexThings);
...
}
public B(){}
[DataMember]
public bool Enabled {get;set;]
[DataMember]
public int Version {
get { return 2; }
set { }
}
[DataMember]
public double TimeInMilliseconds {get;set;}
[DataMember]
public string Name {get;set;}
[DataMember]
public CustomObject2 CustomObject {get;set;} //Also a DataContract
[DataMember]
public List<ComplexThing> ComplexThings {get;set;} //Also a DataContract
...
}
Class A was the first iteration of our object, and is actively in use. Data exists in v1 format, using class A for serialization.
After realizing the error of our ways, we create a new structure called class B. There are so many changes between A and B that we feel it's better to create B, as opposed to adapting the original class A.
But our application already exists and class A is being used to serialize data. We're ready to roll our changes out to the world, but we must first deserialize data created under version 1 (using class A) and instantiate it as class B. The data is significant enough that we can't just assume defaults in class B for missing data, but rather we must transition the data from a class A instance to class B. Once we have a class B instance, the application will serialize that data again in class B format (version 2).
We're assuming we'll make modifications to class B in the future, and we want to be able to iterate to a version 3, perhaps in a new class "C". We have two goals: address data already in existence, and prepare our objects for future migration.
The existing "transition" attributes (OnSerializing/OnSerialized,OnDeserializing/OnDeserialized,etc.) don't provide access to the previous data.
What is the expected practice when using protobuf-net in this scenario?
Right; looking at them you have indeed completely changed the contract. I know of no contract-based serializer that is going to love you for that, and protobuf-net is no different. If you already had a root node, you could do something like (in pseudo-code):
[Contract]
class Wrapper {
[Member] public A A {get;set;}
[Member] public B B {get;set;}
[Member] public C C {get;set;}
}
and just pick whichever of A/B/C is non-null, perhaps adding some conversion operators between them. However, if you just have a naked A in the old data, this gets hard. There are two approaches I can think of:
add lots of shim properties for compatibility; not very maintainable, and I don't recommend it
sniff the Version as an initial step, and tell the serializer what to expect.
For example, you could do:
int version = -1;
using(var reader = new ProtoReader(inputStream)) {
while(reader.ReadFieldHeader() > 0) {
const int VERSION_FIELD_NUMBER = /* todo */;
if(reader.FieldNumber == VERSION_FIELD_NUMBER) {
version = reader.ReadInt32();
// optional short-circuit; we're not expecting 2 Version numbers
break;
} else {
reader.SkipField();
}
}
}
inputStream.Position = 0; // rewind before deserializing
Now you can use the serializer, telling it what version it was serialized as; either via the generic Serializer.Deserialize<T> API, or via a Type instance from the two non-generic APIs (Serializer.NonGeneric.Deserialize or RuntimeTypeModel.Default.Deserialize - either way, you get to the same place; it is really a case of whether generic or non-generic is most convenient).
Then you would need some conversion code between A / B / C - either via your own custom operators / methods, or by something like auto-mapper.
If you don't want any ProtoReader code kicking around, you could also do:
[DataContract]
class VersionStub {
[DataMember(Order=VERSION_FIELD_NUMBER)]
public int Version {get;set;}
}
and run Deserialize<VersionStub>, which will give you access to the Version, which you can then use to do the type-specific deserialize; the main difference here is that the ProtoReader code allows you to short-circuit as soon as you have a version-number.
I don't have an expected practice, but this is what I'd do.
Given you still have access to your V1 class add a property on your V1 class that provides a V2 instance.
In your ProtoAfterDeserialization of V1 create an instance of V2 and seeing it's a Migration I'd suggest manually transfer across what you need (or if it's not too hard, try Merge YMMV).
Also in your ProtoBeforeSerialization throw some form of exception so that you don't attempt to write out the old one any more.
Edit: Examples of using these (VB code)
<ProtoBeforeSerialization()>
Private Sub BeforeSerialisaton()
End Sub
<ProtoAfterSerialization()>
Private Sub AfterSerialisaton()
End Sub
<ProtoBeforeDeserialization()>
Private Sub BeforeDeserialisation()
End Sub
<ProtoAfterDeserialization()>
Private Sub AfterDeserialisation()
End Sub
after seeing your example I hope this satisfied what you are trying to do. Class1 is how you load/convert.
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
public class Class1
{
public Class1()
{
using (FileStream fs = new FileStream("c:\\formatADataFile.dat",
FileMode.Open, FileAccess.Read))
{
A oldA = Serializer.Deserialize<A>(fs);
B newB = oldA.ConvertedToB;
}
}
}
[ProtoContract()]
public class B
{
public B(A a)
{
//Property now has a different name
this.Enabled = a.IsActive;
//Property requires math for correctness
this.TimeInMilliseconds = a.TimeInSeconds * 1000;
this.Name = a.Name;
//Reference objects change, too
this.CustomObject2 = new CustomObject2(a.CustomObj);
this.ComplexThings = new List<ComplexThings>();
this.ComplexThings.AddRange(a.ComplexThings);
//...
}
public B() { }
//[DataMember]
[ProtoMember(1)]
public bool Enabled { get; set; }
//[DataMember]
public int Version
{
get { return 2; }
private set { }
}
[ProtoMember(2)]
public double TimeInMilliseconds { get; set; }
[ProtoMember(3)]
public string Name { get; set; }
[ProtoMember(4)]
public CustomObject2 CustomObject { get; set; } //Also a DataContract
[ProtoMember(5)]
public List<ComplexThing> ComplexThings { get; set; } //Also a DataContract
///...
}
[ProtoContract()]
public class CustomObject2
{
public CustomObject2()
{
Something = string.Empty;
}
[ProtoMember(1)]
public string Something { get; set; }
}
[ProtoContract()]
public class A
{
public A()
{
mBConvert = new B();
}
[ProtoMember(1)]
public bool IsActive { get; set; }
[ProtoMember(2)]
public int VersionNumber
{
get { return 1; }
private set { }
}
[ProtoBeforeSerialization()]
private void NoMoreSavesForA()
{
throw new System.InvalidOperationException("Do Not Save A");
}
private B mBConvert;
[ProtoAfterDeserialization()]
private void TranslateToB()
{
mBConvert = new B(this);
}
public B ConvertedToB
{
get
{
return mBConvert;
}
}
[ProtoMember(3)]
public int TimeInSeconds { get; set; }
[ProtoMember(4)]
public string Name { get; set; }
[ProtoMember(5)]
public CustomObject CustomObj { get; set; } //Also a DataContract
[ProtoMember(6)]
public List<ComplexThing> ComplexThings { get; set; } //Also a DataContract
//...
}
[ProtoContract()]
public class CustomObject
{
public CustomObject()
{
}
[ProtoMember(1)]
public int Something { get; set; }
}
[ProtoContract()]
public class ComplexThing
{
public ComplexThing()
{
}
[ProtoMember(1)]
public int SomeOtherThing { get; set; }
}

Categories