Custom property attribute - c#

Consider the following function, it simply generates an Sql UpdateCommand for an Object
public static string UpdateCommand<T>(this T obj,string idPropertyName, List<string> Except = null, List<string> Only = null)
{
List<PropertyInfo> properties = FilterPropertyList<T>(Except, Only);
StringBuilder query = new StringBuilder();
query.Append("UPDATE " + typeof(T).Name + " SET ");
for (int i = 0; i < properties.Count; i++)
{
if (idPropertyName.ToLower() == properties[i].Name.ToLower())
continue;
query.Append("[" + properties[i].Name + "] = #" + properties[i].Name + ",");
}
if (properties.Count > 1)
{
query.Length -= 2;
}
query.Append(" WHERE " + idPropertyName + "=#" + idPropertyName);
return query.ToString();
}
the second parameter is just the property name which refers to the property name that represents the primary key in the Sql table, i was wondering if its possible to represent that property with an attribute that would be available in the property info, this way i wont have to send it as a parameter.
if this was my object
public class SomeObject
{
//add a custom attribute to the id so it would be recognized in the above function without having to send the property name as a parameter
public int id {get;set;}
public string name {get;set}
}
the following is how i use the function with a SomeObject instance
var someObject = new SomeObject();
var someObjectUpdateCommandString = someObject.UpdateCommand<SomeObject>("id");
can i use some built in attributes, or is it better to create my own attribute?
Here is my try, not sure if its write and i cant seem to use it
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class IsPrimaryKey : Attribute
{
public IsPrimaryKey()
{
this.isPrimaryK = true;
}
private bool isPrimaryK;
public virtual bool IsPrimaryK
{
get { return isPrimaryK; }
set { isPrimaryK = value; }
}
}

The name of the attribute class should end with the Attribute suffix.
Generally, it is a good idea to reuse existing annotations, if they have exactly the purpose that you are looking for, and don't pull unnecessary dependencies.
In your case, the System.ComponentModel.DataAnnotations.KeyAttribute attribute, added in .NET 4.0, would probably fulfill the purpose you are looking for.

Related

changing class property value outside of the class

I have a class say ConstructionSet which is having name property having computed inside get method like as below
public class ConstructionSet
{
[Key]
public Guid Id { get; set; }
public string Name
{
get
{
string climateZonesCsv = (ClimateZones != null && ClimateZones.Any())
? $" - {string.Join(", ", ClimateZones.Select(a => a.Name))}"
: "";
var sourceOfData = !string.IsNullOrEmpty(SourceOfData?.Edition)
? $"{SourceOfData.Name}, {SourceOfData.Edition}"
: SourceOfData?.Name;
return $"{sourceOfData} - {ConstructionMassingType?.Name}{climateZonesCsv}";
}
set { }
}
.......
.......
}
and then I am doing some operations like cloning this ConstructionSet object and appending some text like "copy" to the name property of ConstructionSet after deepclone and it is looks like as below
var targetDhpConstructionSets = sourceDhpConstructionSets.ConvertAll(
dhpcs =>
{
var newDhpConstructionSet = new DesignHubProjectConstructionSet(dhpcs);
var clone = DeepCloner.Clone(dhpcs.SectionObjectRaw);
clone.Name += " (Copy)";
newDhpConstructionSet.AddPatch(employeeContext, clone);
newDhpConstructionSet.IsDefault = dhpcs.IsDefault;
newDhpConstructionSet.Warnings = dhpcs.Warnings;
return newDhpConstructionSet;
});
and below is the image where it shows dhpcs.SectionObjectRaw is indeed a ConstructionSet class object and if i observe the clone object name property value after this line clone.Name += " (Copy)"; the Copy text is not appended.
Could any one please let me know why i am not seeing the appended values to the name property of ConstructionSet
many thanks in advance
because your setter does literally nothing:
set { }
Since your getter obtains several pieces of information on-the-fly, it's not obvious how to change your design to add on arbitrary text to what the getter provides. You could have a "suffix" property that gets appended to the strings that are currently returned, for example. Or have a backing field that the getter populates if it is null, then have the setter change the value of the backing field.
Based on your comments I would probably go with a backing field:
private string _Name;
public string Name
{
get
{
if(this._Name == null) {
string climateZonesCsv = (ClimateZones != null && ClimateZones.Any())
? $" - {string.Join(", ", ClimateZones.Select(a => a.Name))}"
: "";
var sourceOfData = !string.IsNullOrEmpty(SourceOfData?.Edition)
? $"{SourceOfData.Name}, {SourceOfData.Edition}"
: SourceOfData?.Name;
_Name = $"{sourceOfData} - {ConstructionMassingType?.Name}{climateZonesCsv}";
}
return _Name
}
set { _Name = value }
}

Save a custom type in database by using OpenAccess of Telerik

I would like to save in the database a custom type property which is a class.
The property to save is myProperty with the type CustomTypeClass in the below example:
public class Test
{
private CustomTypeClass myProperty;
public CustomTypeClass MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
}
So, the value to save in the database is the result of the ToString override method:
public class CustomType
{
public int Start { get; set; }
public int End { get; set; }
public CustomType(int start, int end)
{
this.Start = start;
this.End = end;
}
public override string ToString()
{
return "[" + this.Start + "," + this.End + "]";
}
}
I would like to perform the following code for saving in the database:
CustomType value = new CustomType(3, 5);
Test test = new Test();
test.myProperty = value;
database.Add(test);
database.SaveChanges();
How can I do this ?
At the moment, I get the following error:
Unsupported field-type 'CustomTypeClass' found for field 'myProperty' of class 'Test'.
Maybe you did not specify the TransientAttribute for this field or the PersistentAttribute is not specified for the referenced class. [class=Test]
I don't think you'll be able to do that since it's not a known attribute within the database. However, What I've done in the past is something like:
//Save logic:
CustomType value = new CustomType(3, 5);
Test test = new Test();
test.myProperty = value.ToString();
database.Add(test);
database.SaveChanges();
And then create a static method on CustomType to convert it from a string back to an object:
var obj = db.Tests.First();
var customType = CustomType.LoadFromString(obj.myProperty);
Where LoadFromString is a static method on the object and converts it from a string back into an object (by parsing the string).

Accessing generic object in generic list in C#

I am relatively new to C# and I would like to create a list of generic objects.
Here is how I try to do it:
I create a base class:
public class BaseClass
{
}
And I inherit a generic class from the base class:
public class GenericClass<T> : BaseClass where T: struct
{
public T data;
public GenericClass(T value)
{
data = value;
}
public T doSomething()
{
return (T)(data * (dynamic)0.826f);
}
}
Then I can create a list of base class:
List<BaseClass> ListOfGenericClasses = new List<BaseClass>();
And I can add instances of the inherited geneic class:
ListOfGenericClasses.Add(new GenericClass<int>(100));
ListOfGenericClasses.Add(new GenericClass<byte>(101));
ListOfGenericClasses.Add(new GenericClass<float>(10.1f));
ListOfGenericClasses.Add(new GenericClass<double>(100.10));
ListOfGenericClasses.Add(new GenericClass<ulong>(9999999999));
ListOfGenericClasses.Add(new GenericClass<long>(-9999999999));
ListOfGenericClasses.Add(new GenericClass<uint>(62389));
ListOfGenericClasses.Add(new GenericClass<sbyte>(-103));
I also can invoke each objects method:
string s = "";
s += ((GenericClass<int>)(ListOfGenericClasses[0])).doSomething() + " # ";
s += ((GenericClass<byte>)(ListOfGenericClasses[1])).doSomething() + " # ";
s += ((GenericClass<float>)(ListOfGenericClasses[2])).doSomething() + " # ";
s += ((GenericClass<double>)(ListOfGenericClasses[3])).doSomething() + " # ";
s += ((GenericClass<ulong>)(ListOfGenericClasses[4])).doSomething() + " # ";
s += ((GenericClass<long>)(ListOfGenericClasses[5])).doSomething() + " # ";
s += ((GenericClass<uint>)(ListOfGenericClasses[6])).doSomething() + " # ";
s += ((GenericClass<sbyte>)(ListOfGenericClasses[7])).doSomething();
MessageBox.Show(s);
And here comes the question: how do I get the value of each instance in the list generally?
I try to do something like this:
string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
s += ((GenericClass<ListOfGenericClasses[i].GetType().GetGenericArguments()[0]>)(ListOfGenericClasses[i])).dosdoSomething() + " # ";
}
MessageBox.Show(s);
I have the following error message: "Using the generic type 'GenericClass requires 1 type argument'"
EDIT: sorry guys I could have been more precize when asking my question: my point was not to use the return value to build a string it was just for seeing the result on screen
Any help is much apreciated,
Thanks in advance
I'd approach it in a slightly different way:
public class BaseClass
{
public virtual string DoSomethingToString() { throw new NotImplementedException(); }
}
Then you'd implement your derived class as follows:
public class GenericClass<T> : BaseClass where T: struct
{
public T data;
public GenericClass(T value)
{
data = value;
}
public T DoSomething()
{
return (T)(data * (dynamic)0.826f);
}
public override string DoSomethingToString()
{
return DoSomething().ToString();
}
}
Now you can iterate List<BaseClass> and directly call each element's DoSomethingToString() method.
Does this do what you want?
string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
Type type = ListOfGenericClasses[i].GetType();
dynamic d = Convert.ChangeType(ListOfGenericClasses[i], type);
s += d.doSomething() + " # ";
}
It looks like you are trying to implement a union type. I am sure there must be better ways than this.
Should you use Generics? I re-wrote your app and solved the problem by removing Generics
public class GenericClass : BaseClass
{
public object data;
public GenericClass(object value)
{
this.data = value;
}
public object doSomething()
{
return (object)(this.data * (dynamic)0.826f);
}
}
Then I did it:
for (var i = 0; i < ListOfGenericClasses.Count; i++)
{
s += ListOfGenericClasses[i].doSomething() + " # ";
}
You would need to use reflection to get the type and then from that get the method which you can then invoke:
string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
s += ListOfGenericClasses[i].GetType()
.GetMethod("doSomething")
.Invoke(ListOfGenericClasses[i], null);
}
However, I would recommend you take the approach as suggested by #corak in the comments and by #InBetween in their answer and create a virtual method in BaseClass and override it in GenericClass.
First use stringBuilder to concat strings, you can cast your object to dynamic to invoke the method you need dynamically:
var stringbuilder = new StringBuilder();
foreach (var l in ListOfGenericClasses)
{
var st = (l as dynamic).doSomething() + " # ";
stringbuilder.Append(st);
}
MessageBox.Show(stringbuilder.ToString());

C# Automatically linking strings to properties using the string value

This might be a stupid one but I'll shoot it out there.
For example let's say I have a model class:
public class PermissionModel
{
public bool AppName_Home_Product_SaveButton_Enabled { get; set; }
public bool AppName_Home_Product_ConfirmButton_Enabled { get; set; }
}
And I have the following list of strings:
"AppName_Home_Product_SaveButton_Enabled_true"
"AppName_Home_Product_SaveButton_Enabled_false"
I want to automatically populate the model properties with true/false without having to use if statements as in the following example:
if (aString.Contains("AppName_Home_Product_SaveButton_Enabled"))
{
PermissionModel.AppName_Home_Product_SaveButton_Enabled = Convert.ToBoolean(AString.Substring(AString.IndexOf("Enabled_") + 8));
}
Any ideas or is this crazy? I just want to avoid a bunch of if statements to populate the model and make it more re-usable.
This can be done via reflection
const string delimiter = "_Enabled";
foreach (string data in aString) {
int index = data.IndexOf(delimiter);
if (index >= 0) {
// Get the name and value out of the data string
string name = data.Substring(0, index + delimiter.Length);
bool value = Convert.ToBoolean(data.Substring(index + delimiter.Length + 1));
// Find the property with the specified name and change the value
PropertyInfo property = GetType().GetProperty(name);
if (property != null) {
property.SetValue(this, value);
}
}
}

How to get current property name via reflection?

I would like to get property name when I'm in it via reflection. Is it possible?
I have code like this:
public CarType Car
{
get { return (Wheel) this["Wheel"];}
set { this["Wheel"] = value; }
}
And because I need more properties like this I would like to do something like this:
public CarType Car
{
get { return (Wheel) this[GetThisPropertyName()];}
set { this[GetThisPropertyName()] = value; }
}
Since properties are really just methods you can do this and clean up the get_ returned:
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Something;
Console.ReadLine();
}
public string Something
{
get
{
return MethodBase.GetCurrentMethod().Name;
}
}
}
If you profile the performance you should find MethodBase.GetCurrentMethod() is miles faster than StackFrame. In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster).
That said I'm sure the performance issue won't cause too much of a problem- though an interesting discussion on StackFrame slowness can be found here.
I guess another option if you were concerned about performance would be to create a Visual Studio Intellisense Code Snippet that creates the property for you and also creates a string that corresponds to the property name.
Slightly confusing example you presented, unless I just don't get it.
From C# 6.0 you can use the nameof operator.
public CarType MyProperty
{
get { return (CarType)this[nameof(MyProperty)]};
set { this[nameof(MyProperty)] = value]};
}
If you have a method that handles your getter/setter anyway, you can use the C# 4.5 CallerMemberName attribute, in this case you don't even need to repeat the name.
public CarType MyProperty
{
get { return Get<CarType>(); }
set { Set(value); }
}
public T Get<T>([CallerMemberName]string name = null)
{
return (T)this[name];
}
public void Set<T>(T value, [CallerMemberName]string name = null)
{
this[name] = value;
}
I'd like to know more about the context in which you need it since it seems to me that you should already know what property you are working with in the property accessor. If you must, though, you could probably use MethodBase.GetCurrentMethod().Name and remove anything after get_/set_.
Update:
Based on your changes, I would say that you should use inheritance rather than reflection. I don't know what data is in your dictionary, but it seems to me that you really want to have different Car classes, say Sedan, Roadster, Buggy, StationWagon, not keep the type in a local variable. Then you would have implementations of methods that do the proper thing for that type of Car. Instead of finding out what kind of car you have, then doing something, you then simply call the appropriate method and the Car object does the right thing based on what type it is.
public interface ICar
{
void Drive( decimal velocity, Orientation orientation );
void Shift( int gear );
...
}
public abstract class Car : ICar
{
public virtual void Drive( decimal velocity, Orientation orientation )
{
...some default implementation...
}
public abstract void Shift( int gear );
...
}
public class AutomaticTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
public class ManualTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
Use MethodBase.GetCurrentMethod() instead!
Reflection is used to do work with types that can't be done at compile time. Getting the name of the property accessor you're in can be decided at compile time so you probably shouldn't use reflection for it.
You get use the accessor method's name from the call stack using System.Diagnostics.StackTrace though.
string GetPropertyName()
{
StackTrace callStackTrace = new StackTrace();
StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
string properyAccessorName = propertyFrame.GetMethod().Name;
return properyAccessorName.Replace("get_","").Replace("set_","");
}
FWIW I implemented a system like this:
[CrmAttribute("firstname")]
public string FirstName
{
get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
}
// this is in a base class, skipped that bit for clairty
public T GetPropValue<T>(string propName)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
return GetAttributeValue<T>(attributeName);
}
public void SetPropValue(string propName, object value)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
SetAttributeValue(attributeName, value);
}
private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
private string GetCrmAttributeName(string propertyName)
{
// keyName for our propertyName to (static) CrmAttributeName cache
string keyName = this.GetType().Name + propertyName;
// have we already done this mapping?
if (!PropToAttributeMap.ContainsKey(keyName))
{
Type t = this.GetType();
PropertyInfo info = t.GetProperty(propertyName);
if (info == null)
{
throw new Exception("Cannot find a propety called " + propertyName);
}
object[] attrs = info.GetCustomAttributes(false);
foreach (object o in attrs)
{
CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
if (attr != null)
{
// found it. Save the mapping for next time.
PropToAttributeMap[keyName] = attr.AttributeName;
return attr.AttributeName;
}
}
throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
}
// return the existing mapping
string result = PropToAttributeMap[keyName];
return result;
}
There's also a custom attribute class called CrmAttributeAttribute.
I'd strongly recommend against using GetStackFrame() as part of your solution, my original version of the solution was originally the much neater:
return GetPropValue<string>();
But it was 600x slower than the version above.
Solution # 1
var a = nameof(SampleMethod); //a == SampleMethod
var b = nameof(SampleVariable); //b == SampleVariable
var c = nameof(SampleProperty); //c == SampleProperty
Solution # 2
MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property
Solution # 3
from StackTrace:
public static class Props
{
public static string CurrPropName =>
(new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");
public static string CurrMethodName =>
(new StackTrace()).GetFrame(1).GetMethod().Name;
}
you just need to call Props.CurrPropName or Props.CurrMethodName
Solution # 4
Solution for .NET 4.5+:
public static class Props
{
public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
return propertyName;
}
}
usage: Props.GetCallerName();
Yes, it is!
string test = "test string";
Type type = test.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
string propName = pi.Name;
}
Try using System.Diagnostics.StackTrace to reflect on the call stack. The property should be somewhere in the call stack (probably at the top if you're calling it directly from the property's code).

Categories