Any idea why private property and variable behave differently in FileHelpers? - c#

To simplify the case, let say I have the following class
public class TestFileHelpersClass
{
[FieldOrder(1), FieldFixedLength(20), FieldTrim(TrimMode.Both)]
public string Field1 { get; set; }
[FieldOrder(2), FieldFixedLength(20), FieldTrim(TrimMode.Both)]
private string Field2 { get; set; }
// If change to a normal variable, there is no exception and FileHelper can work perfectly.
// private string Field2;
public TestFileHelpersClass()
{
this.Field1 = "Field1 Value";
this.Field2 = "Field2 Value";
}
}
Then, there is an exception thrown when I instantiate the FileHelperEngine.
static void TestFileHelpers()
{
// FileHelpers.BadUsageException: 'The field: '<Field2>k__BackingField' must be marked with the FieldFixedLength attribute because the record class is marked with FixedLengthRecord.'
FileHelperEngine<TestFileHelpersClass> engine = new FileHelperEngine<TestFileHelpersClass>();
TestFileHelpersClass a = new TestFileHelpersClass();
string result = engine.WriteString(new List<TestFileHelpersClass> { a });
}
But {Field2} has already been marked with {FieldFixedLength(20)}
If I change {Field2} from a property to variable, it is working fine.
The question is:
When it is public, FileHelpers works perfectly in both the variable and property case.
When it is private, variable is still ok, but property fails to work.
Any idea why private property and variable behave differently in FileHelpers?

When you write autoprops, the compiler generates backing fields for you:
FileHelpers has ReflectionHelper.cs that picks up the fields in a type you want it to parse:
This means, for my dumb class in the first screenshot, it will pick up the two __BackingField, and the two normally named fields:
When FileHelpers is processing these in FieldBase.cs, for any backing fields that have a friendly name, it goes for the property:
fi is the __BackingField; it does have a friendly name because it's come from PrivateProp. To go for the property, FH calls this:
var prop = fi.DeclaringType.GetProperty(fieldFriendlyName);
This call won't discover a private property because it doesn't specify any BindingFlags.NonPublic|BindingFlags.Instance, so prop ends up null and FH doesn't switch to looking at the property
Look back at the first image; the FileHelper custom attributes are on the property, not the backing field. Later in this same FieldBase.cs class, FH tries to find derivates of its own attributes (FH's attributes derive from FieldAttribute) on the member being inspected:
The member being inspected is the __BackingField, which doesn't have any FH attributes; it's the prop that has the attributes. The field does have attributes (CompilerGenerated, DebuggerBrowsable) but because this call looks only for FH's attributes and the backing field doesn't have any FH custom attributes it is essentially looking on the wrong thing. It reaches a situation where it cannot work - it needs attributes you've put on the prop, but it looks on the field, finds no FH attribs and throws an error because it needs those attributes it can never find.
If fi.DeclaringType.GetProperty(fieldFriendlyName) had instead used an overload that looked for private props e.g. fi.DeclaringType.GetProperty(fieldFriendlyName, BindingFlags.NonPublic|BindingFlags.Instance|..other_binding_flags_here) then it would have found the private prop you decorated (but I don't guarantee that this is a bug or that that is the resolution)
You could report a bug and see if the author agrees, you could amend the library yourself and use the amended version, or you could just use fields/public props instead of private props
I cannot answer why the library was coded this way; few people here can. Questions of the ilk "what was developer X thinking when..." are seldom a good fit for SO.

Related

Can I define a custom getter for a C# auto-implemented property (a.k.a. auto backing field)?

Note: I know how to accomplish this without using auto-implemented properties, but I'm wondering if C# has a built-in way to do this.
Let's say I have this simple example of an auto-implemented property (a.k.a. auto backing field):
public class MyClass
{
public MyClass(){}
public string MyString { get; private set; }
}
Now, I would like to return a custom exception in the getter if the auto backing field is null:
public class MyClass
{
public MyClass(){}
public string MyString
{
get
{
return [backing field] ?? throw new Exception("MyString is null");
}
private set;
} = null;
}
Do newer C# versions support something like this? Perhaps there is some syntactic sugar that I can use in place of [backing field] to access the backing field that is automatically created by the compiler?
Note on putting an exception in the getter: I know it shouldn't be a habit. But Microsoft does it occasionally; for example, the property HttpContext.Request.Form will throw an exception if the request is not of the proper content-type.
No, you can not access to backing field in this way.
You must define backing field and validate it.
public class MyClass
{
public MyClass(){}
private string? _myString
public string MyString
{
get
{
return _myString ?? throw new Exception("MyString is null");
}
private set => _myString = value;
} = null;
}
As Fred said, its better to validate it outside of property.
I'm surprised noone mentioned the field keyword, it is exactly what you are asking for (what you would use instead of [backing field] in your example). It was supposed to be shipped with C# 10. It seems it is going to be shipped with C# 11 instead (?)
Search for Field Keyword here.
Put validation in the setter and/or ensure that the constructor sets a valid/non-null default value.
Or make the property nullable to hint to the customer that they have to account for a null value possibility.
Alternatively (but less optimally for multiple reasons), make the property private and add a method for accessing it.
Strongly advise against a property get directly throwing an exception. You or the consumer will dislike the results at some point.

Get property default value as expression using reflection

In order to build a custom transpiler, I'm trying to get the default value of all the properties inside a class as an expression, and not as a value itself.
Let me bring you some examples to clarify what I'm trying to do and what I've done/tried/investigated so far.
Source code could be the following one:
const string DATETIME_NOW = "____DATETIME_NOW____";
public class Person {
[DefaultValue("Foo")]
public string Name { get; set; } = "Foo";
[DefaultValue(DateTime.Now)] // This is not doable: "An attribute argument must be a constant expression"
public DateTime DateOfBirth { get; set; } = DateTime.Now;
[DefaultValue(DATETIME_NOW)]
public string DateOfBirthStringed { get; set; } = DATETIME_NOW; // which acts like DateTime.Now.ToString()
}
The ultimate goal of the transpiler, is to obtain a Javascript class that looks like this:
class Person {
name: string = "Foo";
dateOfBirth: Date = new Date(Date.now());
dateOfBirthStringed : Date = Date.now();
}
My current, and working, implementation is the use of DefaultValue attribute with some constants strings used when the default value is an expression (e.g. DateOfBirthStringed).
What I'm doing is using reflection on Person, getting all the PropertyInfo, looking for their DefaultValue attribute, and then checking if the given default value are some fixed constants like DATETIME_NOW.
This works, but I've a couple of problems:
The type in attribute DefaultValue could be different from the type of the property.. No type check :(
If I only have the DefaultValue, when I write new Person(), the default values are not actually set from the attribute.
Therefore, I need to write the default value after { get; set; }, but:
Or I wrote both attribute and default value, but then I should manually mantain synchronized them.
I write only the default value, but then I've no way to get it with reflection.
About point 3.2, why I can't get the default value via reflection?
Suppose the Person class defined above; if I use reflection, I need to instantiate it, but once instantiated, Person.DateOfBirth has an actual DateTime value, and I cannot know it was coming from DateTime.Now.
Also, if Person would be abstract.. Well, no way to instantiate it.
So, basically, the only way I could perfectly transpile the code is to read the code as a tree, something like parseTreeCode(typeof(Person)). At that point, I should navigate the tree and be able to do everything I want.
I did find Roslyn, which allows me to parse C# code, but.. It parses "stringed" code, and not code that belongs to the same project. I thought "well, get the file where Person is defined, and parse the whole file", but unfortunately, once the program is running, I cannot get the file where Person is defined.. I mean, I can do typeof(Person).Assembly, and getting the Assembly.. But it would be an assembly, so it would not be good.
At this point, I'm thinking that there is no real solution for this, but maybe I'm missing some C# packages/features that could help me

Why do we need Fields if there are Properties?

If the property can store data (as field does) why do we still need field?
For example i have this class,
public class Music
{
public Music() { }
public float musicBPM { get; set; }
public void addBPM()
{
this.muscBPM +=10;
}
}
Its still working like, as I have a private field and change its value, right?
So, whats the critical need of field if you can use the property?
Although automatic properties blur the distinction quite a bit, there is a fundamental difference between a field and a property:
A field is a data member capable of storing things,
A property is a method or a pair of methods which, through help of the compiler, can be used as if they were a field.
In other words, when you write
public float musicBPM { get; set; }
the compiler creates something like this:
private float musicBPM_property;
public float musicBPM {
get { return musicBPM_property; }
set { musicBPM_property = value; }
}
When you make an automatic property, the field is still there, but the compiler cleverly hides it from you.
That is why the fields are going to remain as a concept in .NET. However, automatic read-only properties of C# 6 make it possible to eliminate fields from the code that you write manually.
Property still needs a field as a backing repository, property actually consists of two methods (so called getter and setter) that access that backing field.
From msdn :
A property is a member that provides a flexible mechanism to read,
write, or compute the value of a private field. Properties can be used as if they are public data members, but they are actually special methods called accessors. This enables data to be accessed easily and still helps promote the safety and flexibility of methods.
You don't assign values to your properties ... even though you do that end of the day gets assigned to a variable.
So when you say myprop = 20 the data actually getting assigned to a variable named somevar behind the scene.
public int myprop
{
set { somevar = value; }
}
If you are bit confused seeing auto properties and thinking that you are actually assigning the values to properties then that's not true. Behind the scene compiler will create private backing field to hold those values.
So, in a single sentence; properties gives you a way to encapsulate your class fields.
public int myprop {get; set; }

Should I use a field or a property?

First of all, I have read the question asking for the difference between fields and properties and I know what it is used for.
Now on to my question, I wanted to create a property where I am sure that get and set will both be empty, so I do get; set;. All good and well. But now I realised that I have just made a public field with a capital name, it is in all ways identical.
Even the argument of it being used so future code does not depend on implementation cannot be said, as I can simply make this a property and implement a getter or a setter. The semantics of a field and a property are identical outside the class it is defined in.
So my question is, should I use a field or a property when a property would simply use get;set;?
So this:
public IEnumerable<string> Products;
is identical in all ways to this:
public IEnumerable<string> Products { get; set; }
should I use a field or a property when a property would simply use get;set;?
Use a property... for the practical reasons below, and for the philosophical reasons that properties expose a state API, whereas fields expose a state implementation detail.
The semantics of a field and a property are identical outside the class it is defined in.
That's not true.
The difference is visible via reflection, which is often very important. For example, many binding frameworks won't use fields, only properties.
You can pass a mutable field by ref, but not a property - so changing a field to a property breaks source compatibility. (Code using SomeMethod(ref x.Products) will become invalid when Products becomes a property.)
Changing a field to a property also breaks binary compatibility, so if assembly X was built against assembly Y v1.0, and you change a field to a property for assembly Y v1.1, then you'd need to rebuild assembly X or it would fail to execute correctly
If you have a mutable value type (please don't do this) then writing foo.Location.X = 10 works when Location is a field (because x.Location is classified as a variable) whereas it doesn't when Location is a property (because then the expression x.Location is classified as a value). If you have a method (in your evil mutable type) which mutates the value instead, then foo.Location.DoSomething() will compile in both cases, but have a different effect. Fun for all the family.
Its depend on the situation. I'll prefer to use the property over the field. You have mentioned that public IEnumerable<string> Products; and public IEnumerable<string> Products { get; set; } are same, but in actual they are not. During compilation the property will get converted into two methods (i.e. get_Products() and set_Products()).
The advantage of property is to allows you to specify the custom code before assigning and returning the data, this is not possible with the field. Check the example below
public IEnumerable<string> Products
{
get
{
if(DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//Return future product
return new List<string>();
}
else
{
// return current products
return new List<string>() { "testing" };
}
}
set
{
if (DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//ignore assign product
Products = new List<string>();
}
else
{
// add assign product
Products = value;
}
}
}
Using the auto-property syntax is preferable because it creates a read/write property with a private backing field, thus allowing you to change the implementation (from a private scalar field to a dictionary entry or another backend with some other custom logic), thus freeing the "class's interface" (not the same thing as an interface) from its implementation.
Note that for collection member properties, it is advisable to make their setters private, like so:
public IEnumerable<String> Products { get; private set;}
...that way only the containing class can alter it.
Another alternative is the private readonly field, in C# 6 you can use auto-implemented properties with readonly backing fields like so:
public IEnumerable<String> Products { get; } = SomeSource.GetProducts();

Why can a class not have a static or constant property and an instance property of the same name?

I've never really questioned this before until now. I've got an input model with a number of fields, I wanted to present the string names of the properties through the input model so that my Grid can use them:
public class SomeGridRow
{
public string Code { get;set; }
public string Description { get;set; }
public const string Code = "Code";
}
Obviously, this gives the error:
The type 'SomeGridRow' already
contains a definition for 'Code'
Why can the CLR not cope with two properties of the same name which are, in my eyes, separate?
string code = gridRow.Code; // Actual member from instantiated class
string codeField = SomeGridRow.Code; // Static/Const
I'm now just using a child class called Fields within my inputs now, so I can use SomeGridRow.Fields.Code. It's a bit messy, but it works.
Because you can also access static (or, non-instance in this case) properties in the same way (inside the same class), and it would be a bit confusing, for example:
public class SomeGridRow
{
public string Code { get;set; }
public const string Code = "Code";
public void MyMethod() {
var thing = Code; //what would this reference?
}
}
Because both this:
public class SomeGridRow
{
public string Code { get;set; }
public void MyMethod() {
var thing = Code; //what would this reference?
}
}
And this:
public class SomeGridRow
{
public const string Code = "Code";
public void MyMethod() {
var thing = Code; //what would this reference?
}
}
are valid ways to access properties, static or not. It doesn't answer the "why can't I?" question, but more of the why it's not allowed...it would be far too ambiguous IMO.
It probably could, but the designers of C# wanted to avoid ambiguities that can come from such use (abuse?) of language features.
Such code would end up being confusing and ambiguous to users (did I want the instance or the static method call?, Which one is right?).
In addition to the points already made about ambiguity, i would say that the naming needs to be relooked in such a case.
If two variables / fields having the exact same name in the same context i.e class but different values to me sounds more like a naming issue.
If they are exactly same, you dont need 2 fields.
If they are slightly different, you should have more accurate names.
In some other languages with a similar syntax, one can access a static member through an instance. So you could access both string.Empty and "abc".Empty.
C# doesn't allow this (though it does sort of from inside the class or a derived class, in that you can omit the class name for a static member and can omit this for an instance member), primarily to avoid confusion (I find it more handy than confusion tbh, but that's just me, I like switch fall-through too so what do I know).
Having introduced a stricter rule to allow for less ambiguity, it would be counterproductive to allow a new looser rule on the back of it that allowed for more. Think how many "why must I use this with property X but not property Y?" questions SO would have if it was allowed (we'd have to force this with property X to be clear we meant the instance member).

Categories