I am not too familiar with reflection, however, would it be possible to implement a method that will return an object if that class has a property associated with a certain attribute?
I thought it might make this following implementation not being required
public interface IEntity
{
object ID { get; }
}
public class Person : IEntity
{
[Key]
public int PersonID { get; }
public string Name { get; set; }
public int Age { get; set; }
object IEntity.ID
{
get { return PersonID; }
}
}
So instead of implementing 'IEntity' for every class, you can just do something like this:
public abstract class EntityBase
{
public object ID { get { return FindPrimaryKey(); } }
protected object FindPrimaryKey()
{
object key = null;
try
{
//Reflection magic
}
catch (Exception) { }
return key;
}
}
This would just save some time instead of having to go through all code-first generated classes and implementing this small feature.
Yes, that can definitely be done. Consider the following code:
protected object FindPrimaryKey()
{
object key = null;
var prop = this.GetType()
.GetProperties()
.Where(p => Attribute.IsDefined(p, typeof(Key)))
if (prop != null) { key = prop.GetValue(this); }
return key;
}
However, I would recommend caching that value. Add a private field for the key value:
object _keyValue;
and then set that:
protected void FindPrimaryKey()
{
var prop = this.GetType()
.GetProperties()
.Where(p => Attribute.IsDefined(p, typeof(Key)))
if (prop != null) { _keyValue = prop.GetValue(this); }
}
and then return that instead:
public object ID { get { return _keyValue; } }
Related
I am trying to set the value of a property that is a class.
protected bool TryUpdate(PropertyInfo prop, object value)
{
try
{
prop.SetValue(this, value);
// If not set probably a complex type
if (value != prop.GetValue(this))
{
//... Don't know what to do
}
// If still not set update failed
if (value != prop.GetValue(this))
{
return false;
}
return true;
}
}
I'm calling this method on a number of properties from a variety of classes. This issue is when I have a class like the following:
public class Test
{
public string Name { get; set; }
public string Number { get; set; }
public IComplexObject Object { get; set; }
}
Name and Number are set just fine, but if I try and set an instance of a class that inherits from IComplexObject on Object there is no errors it just remains null.
Is there an easy way to set an instance of a class as property?
So for example if I pass in prop as {IComplexObject Object} and object as
var object = (object) new ComplexObject
{
prop1 = "Property"
prop2 = "OtherProperty"
}
At the end there are no errors but Object remains null and is not set to the instance of ComplexObject. It needs to be generic so I can pass in any class and the property will be updated.
This example works. I've put it for a reference.
I've changed it to await the task and extract the return value to the result variable so you could see that it returns true.
public class Test
{
public string Name { get; set; }
public string Number { get; set; }
public IComplexObject Object { get; set; }
public async Task<bool> TryUpdate(PropertyInfo prop, object value) {
try {
prop.SetValue(this, value);
return true;
}
catch (Exception) {
}
return false;
}
}
public class ComplexObject : IComplexObject
{
}
public interface IComplexObject
{
}
static class Program
{
static void Main() {
TestMethod();
}
static async void TestMethod() {
var test = new Test();
var result = await test.TryUpdate(test.GetType().GetProperty("Object"), new ComplexObject());
}
}
Your code is needlessly complicated, but it works completely fine. I've taken your code and expanded it into a complete example that runs.
The output is this.
Name: asdf, Number: A1B2, Object: hello this is complexobject
It was not null
This shows that the Object property is no different from any of the others. "Complex object" is not a term that really means anything in .net. Additionally your use of async seems unnecessary and confusing.
async void Main() {
Test t = new Test();
Type type = typeof(Test);
await t.TryUpdate(type.GetProperty(nameof(t.Name)), "asdf");
await t.TryUpdate(type.GetProperty(nameof(t.Number)), "A1B2");
await t.TryUpdate(type.GetProperty(nameof(t.Object)), (object)new ComplexObject());
Console.WriteLine(t.ToString());
PropertyInfo prop = type.GetProperty(nameof(t.Object));
if (prop.GetValue(t) == null) {
Console.WriteLine("It was null");
} else {
Console.WriteLine("It was not null");
}
}
public class Test {
public string Name { get; set; }
public string Number { get; set; }
public IComplexObject Object { get; set; }
// Added for the purpose if showing contents
public override string ToString() => $"Name: {Name}, Number: {Number}, Object: {Object}";
// Why is this async? Your code does not await
public async Task<bool> TryUpdate(PropertyInfo prop, object value) {
await Task.Delay(0); // Added to satisfy async
try {
prop.SetValue(this, value);
// If not set probably a complex type
if (value != prop.GetValue(this)) {
//... Don't know what to do
}
return true;
}
catch {
return false;
}
}
}
public interface IComplexObject { }
class ComplexObject : IComplexObject {
public override string ToString() => "hello this is complexobject";
}
For example, I have a class like this:
public class Employee
{
public int Id;
public string Name;
public double Salary;
public DateTime BoD;
}
and a stored procedure that returns only the id and salary columns for employee, what I want using Entity Framework (6 or 5), is the below:
execute the stored procedure, and map its results to an Employee object, without using complex types.
please help me.
Note:
please consider that the procedure will be more complicated, and I don't want to use linq and returns name or Bod.
this is so important in my project.
in nhibernate you can do that.
Here is what you need :
// Create Two Classes
public class Employee
{
public int Id;
public string Name;
public double Salary;
public DateTime BoD;
}
public class EmployeeIDAndSalary
{
public int Id;
public double Salary;
}
// Create Extension Function
// We need to use Automapper extension library.
// Install Automapper using Nuget Package Manager. And create a class and add this code in it.
namespace Models.Mapper
{
public static class EmployeeMapper
{
public static Employee MapToEmployee(this EmployeeIDAndSalary obj)
{
if (obj != null)
{
Employee model = AutoMapper.TryAutoMap<Employee>(obj);
return model ;
}
return new Employee();
}
public static IEnumerable<Employee> MapToEmployee(this IEnumerable<EmployeeIDAndSalary> obj)
{
if (obj != null)
{
return obj.Select(x => x.ConvertToEmployee()).AsEnumerable();
}
return new List<Models.Employee>();
}
}
public static class AutoMapper
{
static AutoMapper()
{
}
public static T TryAutoMap<T>(object fromObject)
{
try
{
var currentObj = Activator.CreateInstance<T>();
var type = currentObj.GetType();
var propInfo = type.GetProperties();
var _type = fromObject.GetType();
foreach (var item in _type.GetProperties())
{
var prop = propInfo.Where(c => c.Name == item.Name).FirstOrDefault();
if (prop != null)
{
// if (prop.GetType().IsAssignableFrom(item.GetType()))
{
if (IsGenericEnumerable(item.PropertyType))
{
continue;
}
if (prop.GetType() == item.GetType())
{
try
{
prop.SetValue(currentObj, item.GetValue(fromObject, null), null);
}
catch { }
}
}
}
}
return currentObj;
}
catch
{
return default(T);
}
}
private static bool IsClass(Type type)
{
return type.IsClass && !type.IsPrimitive;
}
private static bool IsGenericEnumerable(Type type)
{
if (type.FullName.ToLower().Contains("datamodel") || type.FullName.ToLower().Contains("models") || type.FullName.ToLower().Contains("collection"))
{
return true;
}
return false;
}
}
}
// Use Namespace -> Models.Mapper.EmployeeMapper;
// Execute your procedure using EmployeeIdAndSalary
try
{
var _objList = context.SqlQuery<EmployeeIDAndSalary>("YourProcedureName #SpParameterName", param).ToList().MapToEmployee();
}
catch
{ }
// I think this is all what you need.
I've been searching for a while now and tested several methods, but i didn't find the answer i was looking for. I'll try to explain.
I have an object with several fields/properties. These properties have custom attributes.
What i want is to get the custom attribute from a specific propertie without all the knowlege of the object.
The are the base classes
// FieldAttr has a public Text propery
public class TestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1
{
public string Value { get; set; }
}
public class FLDtype2
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public EntityFieldType(string txt)
{
this._text = txt;
}
public string Text { get { return this._text; } }
}
And i want to be able to do this in my application:
static void Main(string[] args)
{
TestObject test = new TestObject();
// (Option 1: preferred)
Console.WriteLine(test.testfld1.getFieldAttr().Text);
// (Option 2)
Console.WriteLine(test.getFieldAttr(test.testfld1).Text);
}
Is this possible? I've seen methods to get custom attribute values from all properties/fields of an object, but not for a specific field.
I've got a working method to get custom attribute from an enum, but wasn't able to recreate it for object fields/properties. This is because i couldn't get the name of the field i was trying to explore, because (for example) test.testfld1.ToString() give's me "ns.FLDtype1".
Looking forward for the answer :)
(and excuse my english)
Yes it is possible:
public static class Extensions
{
public static FieldAttr GetFieldAttr(
this TestObject source,
Expression<Func<TestObject,object>> field)
{
var member = field.Body as MemberExpression;
if (member == null) return null; // or throw exception
var fieldName = member.Member.Name;
var test = typeof (TestObject);
var fieldType = test.GetField(fieldName);
if (fieldType != null)
{
var attribute = fieldType.GetCustomAttribute<FieldAttr>();
return attribute;
}
return null;
}
}
Usage:
TestObject test = new TestObject();
var attr = test.GetFieldAttr(x => x.testfld3);
if(attr != null) Console.WriteLine(attr.Text);
Here is the fiddle
After another day of trial and error I decided to make use of Selman22 answer with a little modification. This is code I created:
public class TestObject : iTestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1 : iField
{
public string Value { get; set; }
}
public class FLDtype2 : iField
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public FieldAttr(string txt)
{
this._txt = txt;
}
public string Text { get { return this._txt; } }
}
public interface iField { }
public interface iTestObject { }
public static class Extensions
{
public static FieldAttr GetFieldAttr<T>(this T source, Expression<Func<iField>> field) where T : iTestObject
{
// Get member body. If no body present, return null
MemberExpression member = (MemberExpression)field.Body;
if (member == null) { return null; }
// Get field info. If no field info present, return null
FieldInfo fieldType = typeof(T).GetField(member.Member.Name);
if (fieldType == null) { return null; }
// Return custom attribute
return fieldType.GetCustomAttribute<FieldAttr>();
}
}
Usage:
public class Program
{
public static void Main()
{
TestObject test = new TestObject();
Console.WriteLine(test.GetFieldAttr(() => test.testfld1).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld2).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld3).Text);
}
}
Uses:
using System;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
I have implemented interfaces to protect the GetFieldAttr method
#Sulman22: Thnx for the response!
I have a similar problem like this :
Many to many object to object relation in C#
However, imagine that the Championship would have a "Last Date Played" property (just as an example) that would map to any Participant. In this case, where would that property end up? Is it a must to create an intermediate class? (which i wouldn't want to do) what option do i have? thanks!
One way would be to have an array on each object containing pointers to the other objects either via an dictionary that stores the object as key and date as value (or a custom property class for any number of properties) or using a wrapper class around the object and a plain list, this wrapper should then implement the decorator pattern to allow direct access to the object together with any unique properties.
The wrapper object could use an internal object for the properties that is shared between the oposing wrapper objects for the 2 different objects so that any property is in sync.
Another way would be a separate list of pairs where one is wrapped like the above.
The later makes it easy to loop over all objects.
Here is a code example, it might not be exactly what you need but it might give you the basics of my idea.
void Main()
{
var p = new Player("David");
var c = new Championship("Chess");
p.LinkChampionship(c, DateTime.Now);
p.Dump();
}
// Define other methods and classes here
class Player : Properties {
public virtual String Name {get; set;}
public List<ChampionshipWrapper> champs = new List<ChampionshipWrapper>();
public Player() {
}
public Player(string name) {
Name = name;
}
public void LinkChampionship(Championship champ, DateTime when) {
var p = new Properties(when);
champs.Add(new ChampionshipWrapper(champ, p));
champ.players.Add(new PlayerWrapper(this, p));
}
}
class Championship : Properties {
public virtual String Name { get; set; }
public List<PlayerWrapper> players = new List<PlayerWrapper>();
public Championship(){}
public Championship(string name) {
Name = name;
}
public void LinkPlayer(Player play, DateTime when) {
var p = new Properties(when);
players.Add(new PlayerWrapper(play, p));
play.champs.Add(new ChampionshipWrapper(this, p));
}
}
class Properties {
public virtual DateTime LastPlayed { get; set; }
public Properties() {
}
public Properties(DateTime when) {
LastPlayed = when;
}
}
class PlayerWrapper : Player {
private Player player;
private Properties props;
public PlayerWrapper(Player play, Properties prop) {
this.player = play;
this.props = prop;
}
public override String Name {
get { return this.player.Name; }
set { this.player.Name = value; }
}
public override DateTime LastPlayed {
get { return this.props.LastPlayed; }
set { this.props.LastPlayed = value; }
}
}
class ChampionshipWrapper : Championship {
private Championship champ;
private Properties props;
public ChampionshipWrapper(Championship c, Properties prop) {
this.champ = c;
this.props = prop;
}
public override String Name {
get { return this.champ.Name; }
set { this.champ.Name = value; }
}
public override DateTime LastPlayed {
get { return this.props.LastPlayed; }
set { this.props.LastPlayed = value; }
}
}
I have a simple object
[ProtoContract]
public class DataChangedEventArgs<T> : EventArgs
{
private readonly object key;
private readonly T data;
private readonly DataChangeType changeType;
///<summary>
/// Key to identify the data item
///</summary>
public object Key
{
get { return key; }
}
[ProtoMember(2, IsRequired = true)]
public T Data
{
get { return data; }
}
[ProtoMember(3, IsRequired = true)]
public DataChangeType ChangeType
{
get { return changeType; }
}
and I have a problem with the key. Its type is object, but it can be either int, long or string.
I would intuitively use a ProtoInclude attribute to say "expect these types" but unfortunately they are class only attribute.
Does anybody has any idea how I could work around this ?
For background, the public object Key is here for historical reasons (and all over the place) so I would very much like to avoid the mother of all refactorings ;-)
Any chance I could get this to Serialize, even force it to Serialize as a string ?
There are indeed a few tricks that might work; the string one you mention is pretty simple (by using a private property marked with [ProtoMember]), but I'm not sure how you would know what type to convert it back to.
There is, however, an inheritance-based ([ProtoInclude]) way to handle a finite number of types (known in advance). Here's a related example, but I'll see I can make it more specific to this case...
With regard to string-based approaches, you could use a prefix? i.e. something like:
public object Key {get;set;}
[ProtoMember(1)]
private object KeyString {
get {
if(Key == null) return null;
if(Key is string) return "s:"+(string)Key;
if(Key is int) return "i:"+Key.ToString();
// etc
}
set {
if(value == null) { Key = null; }
else if(value.StartsWith("s:")) {...}
// etc
}
}
OK; here's an example; I stress that it would be much better to work with fixed keys; the following is a bit ugly, but most of the code can be hidden away and re-used, so maybe not too bad. I'd prefer more strongly-typed keys, though. I might have mentioned that ;-p
using System;
using ProtoBuf;
static class Program
{
static void Main()
{
var message1 = new SomeMessageWithVariableKey<string>(123456, "abcdef");
var clone1 = Serializer.DeepClone(message1);
Console.WriteLine(clone1.Key);
Console.WriteLine(clone1.SomeOtherValue);
var message2 = new SomeMessageWithVariableKey<int>("abcdef", 123456);
var clone2 = Serializer.DeepClone(message2);
Console.WriteLine(clone2.Key);
Console.WriteLine(clone2.SomeOtherValue);
}
}
[ProtoContract]
[ProtoInclude(1, typeof(ProtoKey<int>))]
[ProtoInclude(2, typeof(ProtoKey<string>))]
abstract class ProtoKey
{
public static ProtoKey Create(object key)
{
if (key == null) return null;
if (key is string) return new ProtoKey<string> { Value = key };
if (key is int) return new ProtoKey<int> { Value = key };
throw new ArgumentException("Unexpected key type: " + key.GetType().Name);
}
public abstract object Value { get; protected set;}
public override string ToString()
{
return Convert.ToString(Value);
}
public override bool Equals(object obj)
{
ProtoKey other = obj as ProtoKey;
if (other == null) return false;
return object.Equals(Value, other.Value);
}
public override int GetHashCode()
{
object val = Value;
return val == null ? 0 : val.GetHashCode();
}
}
[ProtoContract]
sealed class ProtoKey<T> : ProtoKey
{
[ProtoMember(1)]
public T TypedValue { get; set; }
public override object Value
{
get { return TypedValue; }
protected set { TypedValue = (T)value; }
}
}
[ProtoContract]
public class SomeMessageWithVariableKey<T>
{
private SomeMessageWithVariableKey() { }
public SomeMessageWithVariableKey(object key, T someOtherValue) {
Key = key;
SomeOtherValue = someOtherValue;
}
public object Key { get; private set; }
[ProtoMember(1)]
private ProtoKey SerializationKey
{
get { return ProtoKey.Create(Key); }
set { Key = value == null ? null : value.Value; }
}
[ProtoMember(2)]
public T SomeOtherValue { get; set; }
}