I have custom attributes and classes which are using those attributes. These attributes are used for Property Grid when class object is selected. Currently both classes and attributes are in the same assembly. Within attributes I have some Form objects. Because of these Form objects I want to keep attributes in a separate assembly. However than it results in a circular reference. Could you please help me on this issue?
Sample:
I have business object whose property can be displayed in PropertyGridControl:
public class Field
{
public Field()
{
}
private int _Type;
[CustomPropertyEditorMarker(typeof(RepositoryItemForFieldDataType))]
public int Type
{
get { return _Type; }
set
{
_Type = value;
}
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomPropertyEditorMarker : Attribute
{
public CustomPropertyEditorMarker(Type editorType)
{
EditorType = editorType;
}
public readonly Type EditorType;
}
public sealed class RepositoryItemForFieldDataType : RepositoryItemLookUpEdit
{
public RepositoryItemForFieldDataType()
{
// Populating LookupEdit details here
}
private void On_ButtonClick()
{
// Here initializing existing Form class and show it
}
}
When Field object is selected, PropertGridControl analyze selected object and checking which property has above Attribute. If yes, then initialize it.
private void SelectObject(object obj)
{
this.Rows.Clear();
this.DefaultEditors.Clear();
this.RepositoryItems.Clear();
if ((this.LastSelectedObject as ApplicationDomainItemBase) != null)
{
(this.LastSelectedObject as ApplicationDomainItemBase).IsSelected = false;
};
this.SelectedObject = null;
this.SelectedObject = obj;
if (!(this.SelectedObject is ConfigurationObjectManagerBase))
{
foreach (var propInfo in this.SelectedObject.GetType().GetProperties())
{
object[] objFieldAtts = propInfo.GetCustomAttributes(typeof(CustomPropertyEditorMarker), true);
if (objFieldAtts != null && objFieldAtts.Length > 0)
{
if (this.GetRowByFieldName(propInfo.Name) != null)
{
RepositoryItem repItem = Activator.CreateInstance(((CustomPropertyEditorMarker)objFieldAtts[0]).EditorType) as RepositoryItem;
this.GetRowByFieldName(propInfo.Name).Properties.RowEdit = repItem;
};
};
};
};
this.LastSelectedObject = obj;
}
Currently both of business object classes and Attributes are within same assembly and need to separate them. However I can't, because business object property is decorated with attribute name and will need to add reference. It will not be possible to add reference because Attribute classes has reference to business object classes. Hope it clear. Thanks.
Without seeing the business object reference that is causing your problem, a general answer is as follows:
Base your business objects on interfaces which would be declared in either the same assembly as where you want to move your attributes, or another "base" assembly. Then refer to the business objects in your attributes via their interfaces.
Related
I have defined the following attribute
[AttributeUsage(AttributeTargets.Class)]
class DemoAttribute : Attribute
{
public string SomeInfo { get; }
public DemoAttribute(string someInfo)
{
this.SomeInfo = someInfo;
}
}
which can be applied to some class as follows:
[Demo("hello world")]
class Program { }
An INamedTypeSymbol variable namedTypeSymbol pointing to the Program class is provided to me with which I managed to get the name of the attribute.
foreach(var attr in namedTypeSymbol.GetAttributes())
{
if(attr.AttributeClass.Name == "DemoAttribute") { ... }
}
But how do I access what was set as SomeInfo?
There are two ways you can pass arguments to attributes. Either by setting the property ([Demo(SomeInfo="hello world")]) or via the constructor, as you are doing. If you used the named approach, Ponas would be correct that the solution lies in NamedArguments.
However, as you are using the constructor, the data is located in ConstructorArguments. This is an array of TypedConstant, from which you can get the value "hello world":
string attributeData = (string)attr.ConstructorArguments[0].Value;
I'm creating a child object from a parent object. So the scenario is that I have an object and a child object which adds a distance property for scenarios where I want to search. I've chosen to use inheritance as my UI works equivalently with either a search object or a list of objects not the result of a location search. So in this case inheritance seems a sensible choice.
As present I need to generate a new object MyObjectSearch from an instance of MyObject. At present I'm doing this in the constructor manually by setting properties one by one. I could use reflection but this would be slow. Is there a better way of achieving this kind of object enhancement?
Hopefully my code below illustrates the scenario.
public class MyObject {
// Some properties and a location.
}
public class MyObjectSearch : MyObject {
public double Distance { get; set; }
public MyObjectSearch(MyObject obj) {
base.Prop1 = obj.Prop1;
base.Prop2 = obj.Prop2;
}
}
And my search function:
public List<MyObjectSearch> DoSearch(Location loc) {
var myObjectSearchList = new List<MyObjectSearch>();
foreach (var object in myObjectList) {
var distance = getDistance();
var myObjectSearch = new MyObjectSearch(object);
myObjectSearch.Distance = distance;
myObjectSearchList.add(myObjectSearch);
}
return myObjectSearchList;
}
The base class needs to define a copy constructor:
public class MyObject
{
protected MyObject(MyObject other)
{
this.Prop1=other.Prop1;
this.Prop2=other.Prop2;
}
public object Prop1 { get; set; }
public object Prop2 { get; set; }
}
public class MyObjectSearch : MyObject
{
public double Distance { get; set; }
public MyObjectSearch(MyObject obj)
: base(obj)
{
this.Distance=0;
}
public MyObjectSearch(MyObjectSearch other)
: base(other)
{
this.Distance=other.Distance;
}
}
This way the setting of properties is handled for all derived classes by the base class.
You can use reflection to copy properties.
public class ChildClass : ParentClass
{
public ChildClass(ParentClass ch)
{
foreach (var prop in ch.GetType().GetProperties())
{
this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(ch, null), null);
}
}
}
There is no easy way to do this, unfortunately. As you said, you would either have to use reflection, or create a "Clone" method that would generate a new child object using a parent object as input, like so:
public class MyObjectSearch : MyObject {
// Other code
public static MyObjectSearch CloneFromMyObject(MyObject obj)
{
var newObj = new MyObjectSearch();
// Copy properties here
obj.Prop1 = newObj.Prop1;
return newObj;
}
}
No matter what, you're either going to end up writing reflection code (which is slow), or writing each property out by hand. It all depends on whether or not you want maintainability (reflection) or speed (manual property copy).
A generic solution would be to serialize it to json and back. In the json-string is no information about the class name from which it was serialized.
Most people do this in javascript.
As you see it works well for pocco objects but i don't guarantee that it works in every complex case. But it does event for not-inherited classes when the properties are matched.
using Newtonsoft.Json;
namespace CastParentToChild
{
public class Program
{
public static void Main(string[] args)
{
var p = new parent();
p.a=111;
var s = JsonConvert.SerializeObject(p);
var c1 = JsonConvert.DeserializeObject<child1>(s);
var c2 = JsonConvert.DeserializeObject<child2>(s);
var foreigner = JsonConvert.DeserializeObject<NoFamily>(s);
bool allWorks = p.a == c1.a && p.a == c2.a && p.a == foreigner.a;
//Your code goes here
Console.WriteLine("Is convertable: "+allWorks + c2.b);
}
}
public class parent{
public int a;
}
public class child1 : parent{
public int b=12345;
}
public class child2 : child1{
}
public class NoFamily{
public int a;
public int b = 99999;
}
// Is not Deserializeable because
// Error 'NoFamily2' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type 'NoFamily2' could be found (are you missing a using directive or an assembly reference?)
public class NoFamily2{
public int b;
}
}
If a shallow copy is enough, you can use the MemberwiseClone method.
Example:
MyObject shallowClone = (MyObject)original.MemberwiseClone();
If you need a deep copy, you can serialize/deserialize like this: https://stackoverflow.com/a/78612/1105687
An example (assuming you write an extension method as suggested in that answer, and you call it DeepClone)
MyObject deepClone = original.DeepClone();
I first came accros this question when I was looking for doing this.
If you are able to work with C# 9 and record-classes. You only have to create a new constructor in the sub-class taking in a base class object and hand it over to the subclass:
public record MyObject {
...
}
public record MyObjectSearch :MyObject
{
public MyObjectSearch(MyObject parent) : base(parent) { }
...
}
Then you can create the child object like this:
MyObject parent = new();
MyObjectSearch m = new MyObjectSearch(parentObj) { Distance = 1.1};
Credits to https://stackoverflow.com/a/64573044/2582968
Seems natural for the base object to have constructor with parameters for its properties:
public class MyObject
{
public MyObject(prop1, prop2, ...)
{
this.Prop1 = prop1;
this.Prop2 = prop2;
}
}
So then, in your descendant object you can have:
public MyObjectSearch(MyObject obj)
:base(obj.Prop1, obj.Prop2)
This reduces duplication related to assignments. You could use reflection to automatically copy all properties, but this way seems more readable.
Note also, that if your classes have so much properties that you're thinking about automatizing of copying of the properties, then they are likely to violate the Single Responsibility Principle, and you should rather consider changing your design.
There are libraries to handle this; but if you just want a quick implementation in a few places, I would definitely go for a "copy constructor" as previously suggested.
One interesting point not mentioned is that if an object is a subclass, then it can access the child's private variables from the within the parent!
So, on the parent add a CloneIntoChild method. In my example:
Order is the parent class
OrderSnapshot is the child class
_bestPrice is a non-readonly private member on Order. But Order can set it for OrderSnapshot.
Example:
public OrderSnapshot CloneIntoChild()
{
OrderSnapshot sn = new OrderSnapshot()
{
_bestPrice = this._bestPrice,
_closed = this._closed,
_opened = this._opened,
_state = this._state
};
return sn;
}
NOTE: Readonly member variables MUST be set in the constructor, so you will have to use the child constructor to set these...
Although I don't like "up-sizing" generally, I use this approach a lot for analytic snapshots...
I have a type SearchBag that holds a bunch of strings and nullable integers to use for passing on search values. I need a way to check if the search bag contains any values.
I'm currently trying to do it like this:
public bool HasValues()
{
return GetType().GetProperties().Any(p => p.GetValue(this, null) != null);
}
But was wondering if there's a better way.
Without modifying the SearchBag type, there isn't a better way.
EDIT: You could change the type to set a boolean flag in every property setter, then check the flag instead of using Reflection.
You could use Post Sharp to intercept the request to change a property value. You could have all search classes inherit from a common class with a List<string>. Then create an aspect attribute to add a property name to that dictionary whenever the value changes. The following is just a sample, and has bugs:
[Serializable]
public class PropertyChangeAwareAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
if (eventArgs.Method.Name.StartsWith("set_"))
((SearchBagBase)eventArgs.Instance).PropertiesChanged.Add(eventArgs.Method.Name);
base.OnEntry(eventArgs);
}
}
abstract class SearchBagBase
{
public List<string> PropertiesChanged = new List<String>();
}
[PropertyChangeAware]
class RegularSearch : SearchBagBase
{
public String Key { get; set; }
}
with usage:
RegularSearch regularSearch = new RegularSearch();
regularSearch.Key = "toys";
regularSearch.PropertiesChanged.ForEach(Console.WriteLine);
I have an object that has properties of another object and one called DataValue, but the type that I want DataValue to return depends on information contained in the object in the other property. I'm not convinced my way is the best way to do this.
I have this business object called an AssetStructure.
An AssetStructure object contains a generic list of IAssetStructureField objects, which are a series of objects that basically hold information about the data that can be held in that field, a default value of a certain datatype and some displaying information properties. Each of the objects implementing the IAssetStructureField interface will hold different datatype. For example, one's DefaultValue's type maybe string and the other maybe a List<ofCustomType>.
I have my Asset object containing a generic list of objects called AssetDataField. The AssetDataField has properties of one containing the AssetStructureField and one called DataValue, the Asset's data for that StructureField.
My problem is datatype of AssetDataField DataValue property, it will need to be different depending on the details of the AssetStructureField object. This StructureField may hold data representing all the user groups with access to the Asset (datatype List<UserGroups>), and another might just be a description field (datatype string), so I need the DataValue coming out of the AssetDataField to be of the same type.
What I'm thinking of doing now, and that I feel can probably be done much better, is having the AssetDataField.DataValue return an object, and then cast it to the typeof the AssetDataField.StructureField.DefaultValue.
object fieldValue;
object fieldDefaultValue;
Asset certainAsset = new Asset(32423);
foreach (AssetDataField dataField in certainAsset.DataFields)
{
fieldDefaultValue = datafield.StructureField.DefaultValue;
fieldValue = datafield.DataValue as typeof(fieldDefaultValue);
// then do stuff depending on what typeof(fieldValue) is. This is where I
// see things getting particularly ugly. Not only just because that
// this class here will need to know the possible types that may be
// returned, so it can deal.
if (typeof(fieldValue) == whatever)
{
// deal;
}
else if (typeof(fieldValue) == whatever2)
{
// deal differently;
}
}
Does anyone have any suggestions? I am not a opposed, at all, to a complete redo. I'm really sorry this is so long-winded, I just wanted to try and explain the situation well. I tried to put together a UML diagram to help out, but my ArgoUML was acting up. Thanks for any insights at all that you can provide.
It seems like you should make AssetDataField a possibly abstract base class, and derive other classes from it to perform the work. For example:
class Program
{
static void Main(string[] args)
{
Asset certainAsset = new Asset(32423);
foreach (AssetDataField dataField in certainAsset.DataFields)
{
dataField.Deal();
}
}
}
class Asset
{
public List<AssetDataField> DataFields = new List<AssetDataField>();
public Asset(int id)
{
// Load asset #id
if (id == 32423)
{
DataFields.Add(new AssetDataFieldString());
DataFields.Add(new AssetDataFieldFloat());
}
}
}
abstract class AssetDataField
{
public AssetDataField()
{
FieldValue = DefaultValue;
}
public abstract object DefaultValue { get; }
public abstract object FieldValue { get; set; }
public abstract void Deal();
}
abstract class AssetDataFieldType<T> : AssetDataField
{
protected T internalValue;
public override object FieldValue
{
get
{
return TypedValue;
}
set
{
TypedValue = (T)System.Convert.ChangeType(value, typeof(T));
}
}
public virtual T TypedValue
{
get
{
return internalValue;
}
set
{
internalValue = value;
}
}
}
class AssetDataFieldString : AssetDataFieldType<string>
{
public override object DefaultValue
{
get { return "Default String"; }
}
// Optionally override TypedValue
public override void Deal()
{
Console.WriteLine(TypedValue.PadLeft(20));
}
}
class AssetDataFieldFloat : AssetDataFieldType<float>
{
public override object DefaultValue
{
get { return 0; }
}
// Optionally override TypedValue
public override void Deal()
{
Console.WriteLine(TypedValue.ToString("#0.000"));
}
}
Note: this smells like the result of querying an EAV based system. In the same way that meta data is the backbone of this sort of system the code referencing it should strive to know what it is accessing (and thus the types) at compile time. That said if you want to simply display the data this sort of thing is required no matter what.
C# is statically typed so you cannot put 'different things' into the same 'slot' (variable, array location) unless the slot is the right 'shape' to take all of them(1). The only slot currently available in c# for this is object. This will work but will box any value types(2).
In c# 4.0 you can use dynamic, which under the hood will be an object but at least will let you invoke any methods on it you want even if the compiler doesn't think it's legal via object.
If all the types in question share a common interface then you can avoid object and get some useful semantics (say if double Sum(double d) was a meaningful operation for any instance you were dealing with then this could yield useful results. However it sounds like you do not control the types present (and thus stand no chance of getting them to conform to useful interfaces).
If the set of possible types is tractable the technique described below can work but it is still cumbersome.
// boxes if needed
public interface IGeneralValue
{
object Value { get; }
Type GetValueType();
}
public class Value<T> : IGeneralValue
{
public T Value { get; set;}
object IGeneralValue.Value
{
get { return (object)this.Value; }
}
public Type GetValueType()
{
return typeof(T);
}
}
Then you can stay statically typed where possible but if not something similar to your previous code will work.
Asset certainAsset = new Asset(32423);
foreach (IGeneralValue dataField in certainAsset.DataFields)
{
object fieldValue = datafield.Value;
Type fieldType = dataField.GetValueType();
if (typeof(double).Equals(fieldType))
{
double d = ((double)fieldValue);
}
else if (typeof(string).Equals(fieldType))
{
string d = ((string)fieldValue);
}
else if (typeof(whatever).Equals(fieldType))
{
// deal with whatever
}
else
{
// the safe option
throw new NotSupportedException(fieldType +" is not supported!");
}
}
Without unsafe code or unions (only structs) at least.
This has implications not just on performance, you cannot unbox an int as a double for example, despite that conversion working on unboxed instances.
I am wanting to access the custom attributes on a Field in the class. I want to access the attributes placed on the field during the fields constructor. Is this possible?
Edit 06/28/09
Something like the below pseudo code
class SpecialInt
{
int _intVal;
int _maxVal;
public SpecialInt()
{
//Get attribute for the instantiated specialint
_maxVal = GetAttribute("MaxValue")
}
}
class main()
{
[MaxValue(100)]
SpecialInt sInt;
public main()
{
sInt = new SpecialInt()
}
}
Sure this is possible. Attributes are stored in Metadata and this is easily accessible during construction of an object.
public class Foo {
[Something]
public int Field1;
public Foo() {
FieldInfo fi = typeof(Foo).GetField("Field1");
SomethingAttribute si = (SomethingAttribute)fi.GetCustomAttribute(typeof(SomethingAttribute),false)[0];
// grab any Custom attribute off of Fiield1 here
}
}
You can test them from anywhere. Attributes are inserted into the metadata for the type when you compile it. A type doesn't need to be instantiated to access field properties.