I have been trying to read the value from the excel sheet, map it into a dataTable and then map the value to its class in C# using reflection. There is no issue for this
I have two classes- one providing test data, and another one providing the logic to read a fixed-width file.
When the two classes have more properties, the way i access to its properties somehow duplicating.
Here is the TestData class
class TestData
{
public string TestName { get; set; }
public string Name{ get; set; }
public string Address{ get; set; }
}
//ignoring the whole logic in the middle, i can access the value of the test by
_testData.Name or _testData.Address
Here is the class to access fixed-width file
class FieldPosition
{
public string FieldName { get; set; }
public string PosStart{ get; set; }
public string PosEnd{ get; set; }
}
class IncomingFields
{
public FieldPosition Name => GetValue("Name");
public FieldPosition Address=> GetValue("Address");
}
//ignoring the whole logic in the middle, i can access the value of the field position by
_field.Name.PosStart or _field.Name.PosEnd
When TestData and IncomingFields have more properties, the code to call them becomes a big duplicating mess. Is there any way to reduce the code since the property name is the same?
Here is what i have to do per one property.
if (_testData.Name != "")
{
ModifyFixedWidthFile(_testData.Name, _field.Name.PosStart, _field.Name.PosEnd)
}
if (_testData.Address!= "")
{
ModifyFixedWidthFile(_testData.Address, _field.Address.PosStart, _field.Address.PosEnd)
}
Is there anyway to reduce 2 if conditions, into 1 block of code by doing a foreach loop? I just don't know how to call the properties in a generic way. is it possible to do something like this in c#
if (_testData.[something generic]!= "")
{
ModifyFixedWidthFile(_testData.[something generic], _field.[something generic].PosStart, _field.[something generic].PosEnd)
}
My names for methods and arguments are all close to useless here.
void OuterMethod(TestData testData, IncomingFields fields)
{
ModifySomething(testData.Address, fields.Address);
ModifySomething(testData.Name, fields.Name);
}
void ModifySomething(string value, FieldPosition fieldPosition)
{
if (value != "")
ModifyFixedWithFile(value, fieldPosition.PosStart, fieldPosition.PosEnd);
}
This just breaks it into two functions. The outer method selects a string property from testData and selects a FieldPosition property from fields. Those are the only parts that are changing. Then it calls the inner ModifySomething method which acts on those values.
Related
How to let an Attribute in one property know the existence of another property?
Lets say i have this class, and like this, many others:
public class MyClass
{
[CheckDirty] //a custom attribute (that it is empty for now)
public int A { get; set; }
public int B { get; set; }
public string Description { get; set; }
public string Info { get; set; }
}
Somewhere in our program, if we want to see if an object changed values on any CheckDirty property, for example lets say it is diferent from DB, MyPropertyUtils.GetPropertiesIfDirty() does this, giving us an array of changed propertys, on any property with that attribute:
PropertyInfo[] MyPropertyUtils.GetPropertiesIfDirty(SomeBaseObject ObjectFromDB, SomeBaseObject NewValues);
Perfect.
So, lets say A changed and in this case Info holds some information we need(in another class might be any other property). If we want 'A' we just do property.GetValue(NewValues, null);
But we dont want 'A's value, we want 'A' or CheckDirty to tell us where to read some data we want. How can i tell my attribute CheckDirty where to get the values from?
I was thinking in giving an expression to CheckDirty but an Attribute's argument "must be a constant expression, typeof expression or array creation expression of an attribute parameter type"(thats what VS says).
So I decided, "ok, lets give it a string with the property's name", and so my try failed:
(this is all the code we need to work on, the rest was just to give some kind of context example)
public class CheckDirty : Attribute
{
public String targetPropertyName;
public CheckDirty(String targetPropertyName)
{
this.targetPropertyName = targetPropertyName;
}
}
public class MyClass
{
//Code fails on this line
[CheckDirty(BoundPropertyNames.Info)]
public int Id { get; set; }
public string Info { get; set; }
public static class BoundPropertyNames
{
public static readonly string Info = ((MemberExpression)
((Expression<Func<MyClass, string>>)
(m => m.Info)
).Body
).Member.Name;
}
}
This is the error i get:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
We do NOT want to pass the name of the proprety as a String saing [CheckDirty("Info")] because that way if anyone in the future changes the class, and in concrete the property's name, no error would get thrown in compile time by it, only occuring the error in run time, when an "edit" to that field would occur. Or maybe it would just not do anything because it could not find the property.
Any idea how to not use the strongly typed string as a property name?
You may use something like this, first declare an interface that will be implemented by every class that need dirty checking:
interface IDirtyCheckPropertiesProvider {
string GetPropertyName(string dirtyProperty);
}
then implement it like that
class DataEntity : IDirtyCheckPropertiesProvider {
[CheckDirty]
public int Id { get; set; }
public string Info { get; set; }
string GetPropertyName(string dirtyProperty) {
if (GetPropertyNameFromExpression(x => Id) == dirtyProperty)
return GetPropertyNameFromExpression(x => Info);
return null;
}
}
In class that will be responsible for handling dirty checks you must use this interface to get target property names.
There is a bit too much boilerplate that may be removed further by using Reflection API.
On the other hand using string for property names looks like more simple solution. If you use tool like Resharper - using string is a viable option - Resharper will automatically refactor string when you change property name.
Also for a long time string'ed property names were used in implementation of WPF INotifyPropertyChanged.
As comments suggested nameof is the best option in VS2015.
When refactoring code, I come up with instances like the following
private string _property = string.Empty;
public string Property
{
set { _property = value ?? string.Empty); }
}
Later on in a method I see the following:
if (_property != null)
{
//...
}
Assuming that _property is only set by the setter of Property, is this code redundant?
I.e is there any way, through reflection wizardry or other methods that _property can ever be null?
Assuming that _property is only set by the setter of Property, is this
code redundant?
Exactly, it is redundant. This is the actual purpose of Properties. We shouldn't access the fields of a class directly. We should access them using a Property. So in the corresponding setter, we can embed any logic and we can rest assure that each time we try to set a value this logic would be verified once more.This argument holds even for the methods of a class. In a method we must use the properties and not the actual fields. Furthermore, when we want to read the value of a field, we should make use of the corresponding getter.
In general, properties enhances the concept of encapsulation, which is one of the pillars of object oriented programming OOP.
Many times there isn't any logic that should be applied when we want to set a value. Take for instance the following example:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
We have declared a class for representing a Customer. A Customer object should have three properties an Id, a FirstName and a LastName.
An immediate question, when someones read this class is why should someone make use of properties here?
The answer is again the same, they provide a mechanism of encapsulation. But let's consider how can this help us in the long run. Let's say that one day someone decides that the first name of a customer should be a string of length less than 20. If the above class had been declared as below:
public class Customer
{
public int Id;
public string FirstName;
public string LastName;
}
then we should check for the length of FirstName in each instance we had created ! Otherwise, if we had picked the declaration with the properties, we could just easily make use of Data Annotations
public class Customer
{
public int Id { get; set; }
[StringLength(20)]
public string FirstName { get; set; }
public string LastName { get; set; }
}
and that's it. Another approach it could be the following:
public class Customer
{
public int Id { get; set; }
private string firstName;
public string FirstName
{
get { return firstName }
set
{
if(value!=null && value.length<20)
{
firstName = value;
}
else
{
throw new ArgumentException("The first name must have at maxium 20 characters", "value");
}
}
}
public string LastName { get; set; }
}
Consider both of the above approaches with having to revisit all your codebase and make this check. It's crystal clear that properties win.
Yes, it is possible through reflection. Nevertheless, I wouldn't worry about reflection -- people using reflection to defeat the design of your class is not something I worry about.
There is, however, something I do worry about: the phrase "Assuming that _property is only set by the setter of Property" is key. You are preventing users of your class from setting property to null.
You do not prevent, however, yourself or some other maintainer of your class from forgetting to only use the property INSIDE your class. In fact, your example has some one checking the field from inside the class rather than the property itself.... which means that, within your class, access comes from both the field and the property.
In most cases (where the problem could only come from inside the class) I would use an assertion and assert the field is not null.
If I really, really, really wanted to make sure that it wasn't null (barring reflection or people hell-bent on breaking things), you could try something like this:
internal class Program
{
static void Main()
{
string example = "Spencer the Cat";
UsesNeverNull neverNullUser = new UsesNeverNull(example);
Console.WriteLine(neverNullUser.TheString);
neverNullUser.TheString = null;
Debug.Assert(neverNullUser.TheString != null);
Console.WriteLine(neverNullUser.TheString);
neverNullUser.TheString = "Maximus the Bird";
Console.WriteLine(neverNullUser.TheString);
}
}
public class UsesNeverNull
{
public string TheString
{
get { return _stringValue.Value; }
set { _stringValue.Value = value; }
}
public UsesNeverNull(string s)
{
TheString = s;
}
private readonly NeverNull<string> _stringValue = new NeverNull<string>(string.Empty, str => str ?? string.Empty);
}
public class NeverNull<T> where T : class
{
public NeverNull(T initialValue, Func<T, T> nullProtector)
{
if (nullProtector == null)
{
var ex = new ArgumentNullException(nameof(nullProtector));
throw ex;
}
_value = nullProtector(initialValue);
_nullProtector = nullProtector;
}
public T Value
{
get { return _nullProtector(_value); }
set { _value = _nullProtector(value); }
}
private T _value;
private readonly Func<T, T> _nullProtector;
}
It is basically redundant. However, if it were mission critical or if for some reason it caused terrible side effects, it could remain. It is hard to tell, but part of your question was "can reflection change this value to null" to which the answer is yes and can be seen here in this linqpad demo
void Main()
{
var test = new Test();
test.Property = "5";
Console.WriteLine(test.Property);//5
FieldInfo fieldInfo = test.GetType().GetField("_property",BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(test, null);
Console.WriteLine(test.Property);//null
}
public class Test
{
private string _property = string.Empty;
public string Property
{
get { return _property; }
set { _property = value ?? string.Empty; }
}
}
I know this question is old, but look, I needed that one of my string properties never came up in null.
So I did this, and It worked for me
public string Operation { get; set; } = string.Empty;
In this way the default value is a string empty, but never null.
As the code illustrates, passing down parameters is a rather frequent task. Instead of writing them by hand, is there a way to auto-generate the list isPriority, label, id, start, user with Resharper, Visual Studio natively, or another add-on?
public void TransformAndStore(
bool isPriority,
string label,
string id,
DateTimeOffset start,
string user)
{
if (this.IsValid(id)) {
label = this.Clean(label);
this.Reposit(isPriority, label, id, start, user);
}
}
The list generated should be based on the method signature, listing all parameters of the method without their types, in the order they appear.
Additionally, if the Reposit method were to use some but not all of the same parameters available in the calling method scope, as identified by parameter/variable names, then autocompleting that would speed up coding as well, and reduce RSI :)
You could create a class to store all the parameters so you only need to pass a single item around. Resharper can do this for you automatically by using Refactor -> Extract -> Extract class from parameters.
Also if you are always repeating the same groups of parameters, consider moving the methods that act upon them into the class too. Logically grouping the data with the methods can be a good practice. For example:
public class CleverName
{
public bool IsPriority { get; set; }
public string Label { get; set; }
public string Id { get; set; }
public DateTimeOffset Start { get; set; }
public string User { get; set; }
public bool IsValid()
{
//Check if Id is valid
}
public void TransformAndStore()
{
if (this.IsValid()) {
Label = this.Clean(Label);
this.Reposit();
}
}
public void Reposit()
{
}
}
While it doesn't answer the exact question you're asking, take a look at ReSharper's Smart Completion. It will filter the available items for completion based on the current context, and is often really good at suggesting exactly the right parameter to pass through.
I have a module that iterates through the public properties of an object (using Type.GetProperties()), and performs various operations on these properties. However, sometimes some of the properties should be handled differently, e.g., ignored. For example, suppose I have the following class:
class TestClass
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
Now, I would like to be able to specify that whenever my module gets an object of type TestClass, the property Prop2 should be ignored. Ideally I would like to be able to say something like this:
ReflectionIterator.AddToIgnoreList(TestClass::Prop2);
but that obviously doesn't work. I know I can get a PropertyInfo object if I first make an instance of the class, but it doesn't seem right to create an artificial instance just to do this. Is there any other way I can get a PropertyInfo-object for TestClass::Prop2?
(For the record, my current solution uses string literals, which are then compared with each property iterated through, like this:
ReflectionIterator.AddToIgnoreList("NamespaceName.TestClass.Prop2");
and then when iterating over the properties:
foreach (var propinfo in obj.GetProperties())
{
if (ignoredProperties.Contains(obj.GetType().FullName + "." + propinfo.Name))
// Ignore
// ...
}
but this solution seems a bit messy and error-prone...)
List<PropertyInfo> ignoredList = ...
ignoredList.Add(typeof(TestClass).GetProperty("Prop2"));
should do the job... just check whether ignoredList.Contains(propinfo)
Could you add attributes to the properties to define how they should be used? eg
class TestClass
{
public int Prop1 { get; set; }
[Ignore]
public int Prop2 { get; set; }
}
Considering the class below
- can I do anything to implement a case-insensitive string?
public class Attibute
{
// The Name should be case-insensitive
public string Name
{
get;
set;
}
public Attibute()
{
}
}
public class ClassWithAttributes
{
private List<Attributes> _attributes;
public ClassWithAttributes(){}
public AddAttribute(Attribute attribute)
{
// Whats the best way to implement the check?
_attributes.add(attribute);
}
}
Structure of an HTML 4 Document
I have edited the class to be a bit more objective and specific
In answer to the restructured question, you could do it like this:
public class Attribute { public string Name { get; set; } }
public class AttributeCollection : KeyedCollection<string, Attribute> {
public AttributeCollection() : base(StringComparer.OrdinalIgnoreCase) { }
protected override string GetKeyForItem(Attribute item) { return item.Name; }
}
public class ClassWithAttributes {
private AttributeCollection _attributes;
public void AddAttribute(Attribute attribute) {
_attributes.Add(attribute);
//KeyedCollection will throw an exception
//if there is already an attribute with
//the same (case insensitive) name.
}
}
If you use this, you should either make Attribute.Name read-only or call ChangeKeyForItem whenever it's changed.
You can't have case-insensitive properties—you can only have case-insensitive operations, like a comparison. If someone accesses XHtmlOneDTDElementAttibute.Name, they will get back a string with whatever case it was created with.
Whenever you use .Name, you can implement that method in a way that ignores the case of the string.
It depends what you're trying to do with the strings.
If you want to compare strings regardless of case, call String.Equals with StringComparison.OrdinalIgnoreCase.
If you want to put them in a dictionary, make the dictionary's comparer StringComparer.OrdinalIgnoreCase.
Therefore, you could make a function as follows:
public class XHtmlOneDTDElementAttibute : ElementRegion {
public bool IsTag(string tag) {
return Name.Equals(tag, StringComparison.OrdinalIgnoreCase);
}
// The Name should be case-insensitive
public string Name { get; set; }
// The Value should be case-sensitive
public string Value { get; set; }
}
If you want a more specific solution, please tell me what you're doing with the Name property
Well, my take on this, after glancing at the spec, is that there's nothing you need to do to make the string properties case-insensitive. The concept doesn't really make sense, anyway: strings aren't case-sensitive or -insensitive; operations on them (like search and sort) are.
(I know the W3C's HTML recommendations say essentially that. It's badly-phrased.)
Alternatively, you might want to make the property always uppercase, like this.
public class XHtmlOneDTDElementAttibute : ElementRegion {
string name;
// The Name should be case-insensitive
public string Name {
get { return name; }
set { name = value.ToUpperInvariant(); }
}
// The Value should be case-sensitive
public string Value { get; set; }
}