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; }
}
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";
}
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; } }
Within code I want to do something like this:
item.Stage = Stage.Values.ONE;
Where Stage.Values.ONE represents some predefined Stage:
public class Stage
{
[Key]
public virtual int StageId { get; set; }
public string Name { get; set; }
public TimeSpan Span { get; set; }
}
I'm dealing with EF CodeFirst... and I have a lot of stages to define. I'm not sure if I should store the data in the database, or in the dbContext, or what, but I'm looking for the simplest implementation.
I've tried this:
I've tried the following (defining two constants):
public class Stage
{
[Key]
public virtual int StageId { get; set; }
public string Name { get; set; }
public TimeSpan Span { get; set; }
public static class Values
{
public static readonly Stage ONE = new Stage()
{
StageId = 0,
Name = "ONE",
Span = new TimeSpan(0, 0, 0)
};
public static readonly Stage TWO = new Stage()
{
StageId = 1,
Name = "TWO",
Span = new TimeSpan(0, 0, 10)
};
}
But whenever I create a new instance of an entity that has a Stage, a new Stage is added to the db. I just need a few constant stages.
Use of Stage:
public class Side
{
public Side()
{
Stage = Stage.Values.ONE; // Adds new Stage to DB, when it should be a reference to the one I defined above
}
public virtual Stage Stage { get; set; }
}
It looks a bit like an enum, and I've used a kind of 'extended enum' patter several times before with some success. Because you're refencing these values in code, it may not make sense to store them in the database as well, but it's possible if needed.
The technique is described in detail here: http://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/
Basically, you create a base class which provides a number of services similar to an enum, and then to create your "enumerated class" you inherit from it and provide a bunch of static instances which call the constructor with however many properties you need to have.
To avoid link rot, here is the base class to use (just put the whole class into your project somewhere), and scroll down for your own code.
public abstract class Enumeration : IComparable
{
private readonly int _value;
private readonly string _displayName;
protected Enumeration()
{
}
protected Enumeration(int value, string displayName)
{
_value = value;
_displayName = displayName;
}
public int Value
{
get { return _value; }
}
public string DisplayName
{
get { return _displayName; }
}
public override string ToString()
{
return DisplayName;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration, new()
{
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var info in fields)
{
var instance = new T();
var locatedValue = info.GetValue(instance) as T;
if (locatedValue != null)
{
yield return locatedValue;
}
}
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = _value.Equals(otherValue.Value);
return typeMatches && valueMatches;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue)
{
var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
return absoluteDifference;
}
public static T FromValue<T>(int value) where T : Enumeration, new()
{
var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
return matchingItem;
}
public static T FromDisplayName<T>(string displayName) where T : Enumeration, new()
{
var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
return matchingItem;
}
private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : Enumeration, new()
{
var matchingItem = GetAll<T>().FirstOrDefault(predicate);
if (matchingItem == null)
{
var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
throw new ApplicationException(message);
}
return matchingItem;
}
public int CompareTo(object other)
{
return Value.CompareTo(((Enumeration)other).Value);
}
}
And now your code will look something like this:
public class Stage : Enumeration
{
public TimeSpan TimeSpan { get; private set; }
public static readonly Stage One
= new Stage (1, "Stage one", new TimeSpan(5));
public static readonly Stage Two
= new Stage (2, "Stage two", new TimeSpan(10));
public static readonly Stage Three
= new Stage (3, "Stage three", new TimeSpan(15));
private EmployeeType() { }
private EmployeeType(int value, string displayName, TimeSpan span) : base(value, displayName)
{
TimeSpan = span;
}
}
Once you have that set up, you can just store the .Value in the database. I'm afraid I haven't done it in EF, but in nHibernate it's reasonably straight-forward to tell a property to just store the ".Value" of the property, and you can wire it back up when you load the value by having it call:
Stage.FromValue<Stage>(intValue);
Hold the Stage as a property of your entity, use it the way you're doing and add
Ignore(x => x.Stage)
to your mapping. This will ignore this property when mapping to your database.
Edit: I misinterpreted the question.
If you want just the different stages in your database, you should put the stages in their own table with an ID, and refer to that ID trough a relationship. Every entity will hold an additional reference and you'll have to define relationships for them.
Is this what you were looking for?
I was wondering if it's possible to run the following code but without the unboxing line:-
t.Value = (T)x;
Or maybe if there is another way to do this kind of operation?
Here is the full code:-
public class ValueWrapper<T>
{
public T Value { get; set; }
public bool HasValue { get; set; }
public ValueWrapper()
{
HasValue = false;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
myDictionary.Add("key1", 6);
myDictionary.Add("key2", "a string");
var x2 = GetValue<int>(myDictionary, "key1");
if (x2.HasValue)
Console.WriteLine("'{0}' = {1}", "key1", x2.Value);
else
Console.WriteLine("No value found");
Console.ReadLine();
}
static ValueWrapper<T> GetValue<T>(IDictionary<string, object> dictionary, string key)
{
ValueWrapper<T> t = new ValueWrapper<T>();
object x = null;
if (dictionary.TryGetValue(key, out x))
{
if (x.GetType() == typeof(T))
{
t.Value = (T)x;
t.HasValue = true;
}
}
return t;
}
}
Thanks in advance!!
Richard.
A few comments:
t.Value = (T)x;
The cast is necessary. This is because t.Value is of type T and x is of type object. The strongly-typed nature of C# requires that you tell the compiler "look, I know this might unsafe but can you just try to do it for me anyway, either by conversion or unboxing or whatever? Thanks!"
2.
object x = null;
if (dictionary.TryGetValue(key, out x)) {
if (x.GetType() == typeof(T)) {
t.Value = (T)x;
t.HasValue = true;
}
}
return t;
What if x is an instance of a class that derives from T? Or if x is an instance of a class that implements an interface and T is that interface? Right now, you will return a instance of ValueWrapper<T> that indicates there was no object in the dictionary with the key key. I would argue this is very counterintuitive to what most people expect.
Additionally, if you're not going to throw up when dictionary does not contain a value matching the key key, I think you should rename your method to TryGetValue, accept a out parameter of type ValueWrapper<T>, and return a bool indicating success/failure.
3.
Responding to your comment, here's one solution.
public interface IValueWrapper {
object Value { get; set; }
bool HasValue { get; set; }
}
public class ValueWrapper<T> : IValueWrapper {
public T Value { get; set; }
object IValueWrapper.Value {
get { return Value; }
set { this.Value = (T)value; }
}
public bool HasValue { get; set; }
public ValueWrapper() {
this.HasValue = false;
}
public ValueWrapper(T value) {
this.Value = value;
this.HasValue = value != null;
}
}
public static class DictionaryExtensions {
public static void Add<T>(
this IDictionary<string, IValueWrapper> dictionary,
string key,
T value
) {
ValueWrapper<T> valueWrapper = new ValueWrapper<T>(value);
dictionary.Add(key, valueWrapper);
}
public static bool TryGetWrappedValue<T>(
IDictionary<string, IValueWrapper> dictionary,
string key,
out ValueWrapper<T> value
) {
IValueWrapper valueWrapper;
if (dictionary.TryGetValue(key, out valueWrapper)) {
value = (ValueWrapper<T>)valueWrapper;
return true;
}
else {
value = null;
return false;
}
}
}
Usage:
var dict = new Dictionary<string, IValueWrapper>();
dict.Add("hello", 5);
ValueWrapper<int> value;
dict.TryGetWrappedValue("hello", out value);
You'll have to add parameter checking etc.
I have this code (which is way simplified from the real code):
public interface IAmount
{
decimal Amount { get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount { get; set; }
}
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
amount.Amount = GetAmount();
}
public static decimal GetAmount()
{
return 12345m;
}
The code works great and the UpdateAmounts ExtensionMethod is used quite frequently throughout the application to apply a penny rounding routine (not like the one in Office Space!)
The problem is I do not like having an IAmount interface with a specific name of the column I need to set (Amount). In a new requirement, I need to update a database entity collection with this routine and the name of the property I need to update is "GrossAmount". Sometimes too it would be nice to update other writable decimal properties in a similar manner.
The problem is that it appears I cannot simple say amount.Field = GetAmount() where the .Field part deals with a different property on the entity. Is it possible somehow? I am not on C# 4.0, so using a dynamic type isn't possible for me yet.
You could do this in a more functional style, something like this:
public class Something
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void UpdateAmounts<T, U>(IEnumerable<T> items, Action<T,U> setter, Func<T, U> getter)
{
foreach (var o in items)
{
setter(o, getter(o));
}
}
public void QuickTest()
{
var s = new [] { new Something() { Amount = 1, OtherAmount = 11 }, new Something() { Amount = 2, OtherAmount = 22 }};
UpdateAmounts(s, (o,v) => o.Amount = v, (o) => o.Amount + 1);
UpdateAmounts(s, (o,v) => o.OtherAmount = v, (o) => o.OtherAmount + 2);
}
What about having a Dictionary-like interface ?
public interface IAmount {
decimal this[string fieldName] { get; set; }
}
Implementation is simply:
public class Money : IAmout {
private Dictionary<string, decimal> _dict;
public decimal this[string fieldName] {
get { return _dict[fieldName]; }
set { _dict[fieldName] = value; }
}
}
(of course, it requires some error checking)
Then, one can write:
Money m = new Money();
m["Amount"] = ...
or
m["GrossAmount"] = ...
Not as nice as dynamic, I agree.
public class SomeAmount : IAmount
{
decimal amount;
public decimal Amount
{
get{return this.amount;}
set{this.amount=value; }
}
}
Not sure how willing you are to screw with your entities, but...
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount { get; set; }
decimal IAmount.Amount
{
get { return GrossAmount; }
set { GrossAmount = value; }
}
}
This hides the Amount implementation of your entity in any context that it's not directly used as an IAmount, while still allowing it to function as an IAmount.
You could hide the Field property, like this:
public interface IAmount
{
decimal Field
{ get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount
{ get; set; }
decimal IAmount.Field
{
get { return Amount; }
set { Amount = value; }
}
}
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount
{ get; set; }
decimal IAmount.Field
{
get { return GrossAmount; }
set { GrossAmount= value; }
}
}
Casting the object to IAmount reveals the Field for your purposes. Otherwise, Field is hidden in the designer and Amount (or GrossAmount) is what you'll be working with.
You could also use reflection in order to apply your rounding on every decimal inside your type.
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
{
var myType = amount.GetType();
var myTypeProperties = myType.GetProperties();
foreach (PropertyInfo h_pi in myTypeProperties)
{
if (h_pi.Property_Type == typeof(decimal)) // or h_pi.Name == "Amount" || h_pi.Name == "GrossAmount"...
{
//DoStuff
}
}
}
amount.Amount = GetAmount();
}
there is better way to write that but I'm sure you get the point. Using reflection you could also get rid of the whole interface thing and simply go by reflection.
P.S. : Reflection is not the fastest way to go but it's an easy way to get runtime flexibility.
Let me know if that's what you wanted...
Or, when you do not mind using reflection (it is a bit slower): it is very powerful in combination with attributes. First, create an attribute used to mark the decimal property you need:
[AttributeUsage(AttributeTargets.Property,
Inherited = true, AllowMultiple = false)]
sealed class DecimalFieldAttribute : Attribute
{
public DecimalFieldAttribute()
{ }
}
Mark your field with the attribute, e.g.:
public class SomeGrossAmount
{
[DecimalField]
public decimal GrossAmount
{
get;
set;
}
}
Then use this method to set such a field:
public static void SetDecimalField(object obj, decimal value)
{
// Enumerate through all the properties to find one marked
// with the DecimalFieldAttribute.
PropertyInfo[] properties = obj.GetType().GetProperties();
PropertyInfo decimalfieldproperty = null;
foreach (PropertyInfo property in properties)
{
object[] attributes = property.GetCustomAttributes(typeof(DecimalFieldAttribute), true);
if (attributes.Length == 0)
continue;
// Check, or just break; when you'll not be making this error.
if (decimalfieldproperty != null)
throw new Exception("More than one property is marked with the DecimalFieldAttribute.");
// Found a candidate.
decimalfieldproperty = property;
}
// Check, or just assume that you'll not be making this error.
if (decimalfieldproperty == null)
throw new Exception("No property with the DecimalFieldAttribute found.");
// Set the value.
decimalfieldproperty.SetValue(obj, value, null);
}
I would suggest something like this:
public class Entity
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void Update<TEntity, TValue>(this IEnumerable<TEntity> entities, Func<TValue> valueGetter, Action<TEntity, TValue> valueSetter)
{
foreach (TEntity entity in entities)
{
TValue value = valueGetter.Invoke();
valueSetter.Invoke(entity, value);
}
}
public static decimal GetAmount()
{
throw new NotImplementedException();
}
public static decimal GetOtherAmount()
{
throw new NotImplementedException();
}
public static IEnumerable<Entity> GetEntities()
{
throw new NotImplementedException();
}
static void Main()
{
IEnumerable<Entity> entities = GetEntities();
entities.Update<Entity, decimal>(GetAmount, (entity, value) => entity.Amount = value);
entities.Update<Entity, decimal>(GetOtherAmount, (entity, otherValue) => entity.OtherAmount = otherValue);
}