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.
Related
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.
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 am using CodeDom to generate a class which include some methods. I was able to declare an attribute for my methods to look similar as what Pex does when it creates a parameterized unit test:
[PexMethod]
public void myMethod()
However I would like to include something more to it like:
[PexMethod (Max Branches = 1000)]
public void myMethod()
But I am not able to include the ((Max Branches = 1000)). Could you somebody help me a bit?
You can't have spaces in the attribute values, they are just wrappers around public properties in your custom attributes class. For example:
public class TestAttribute : Attribute
{
public bool Enabled { get; set; }
}
And you can use this like this
[TestAttribute(Enabled = true)]
void Foo(){}
So since the attribute maps to a property it has to follow normal syntactical naming rules.
I'm not sure what your problem is, but you can simply set the Value property on CodeAttributeArgument:
var method =
new CodeMemberMethod
{
Name = "MyMethod",
CustomAttributes =
{
new CodeAttributeDeclaration
{
Name = "PexMethod",
Arguments =
{
new CodeAttributeArgument
{
Name = "MaxBranches",
Value = new CodePrimitiveExpression(1000)
}
}
}
}
};
The MaxBranches property is on a base class (PexSettingsAttributeBase). That may be why you are having trouble. You may be reflecting over the wrong type to find the PropertyInfo to set.
CodeAttributeArgument codeAttr = new CodeAttributeArgument(new CodePrimitiveExpression("Max Branches = 1000"));
CodeAttributeDeclaration codeAttrDecl = new CodeAttributeDeclaration("PexMethod",codeAttr);
mymethod.CustomAttributes.Add(codeAttrDecl);
I am converting a Delphi code to a C#.
I have a complex classes structure where a class is the main 'trunk' of all its children.
In Delphi I can define the private/protected field with a type and the property for that field with the same type, and not write the type in child classes anymore.
Here is a bit (and functional) example:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
Parent = class
strict protected
_myFirstField: Int64;
public
property MyFirstField: Int64 write _myFirstField;
end;
Child1 = class(Parent)
public
// Inherits the write/set behaviour..
// And it doesn't need to define the type 'over and over' on all child classes.
//
// ******* Note MyFirstField here has not type.... ************
property MyFirstField read _myFirstField; // Adding READ behaviour to the property.
end;
var
Child1Instance: Child1;
begin
Child1Instance := Child1.Create;
//Child1Instance.MyFirstField := 'An String'; <<-- Compilation error because type
Child1Instance.MyFirstField := 11111;
WriteLn(IntToStr(Child1Instance.MyFirstField));
ReadLn;
end.
As you can see I don't need to define the property type over and over.
If I need to change the var type in the future, I can change only in the parent class.
Is there any way to get this same behaviour in C#?
No, there ist. The types on the public API must be explicit. The only time you aren't explicit is with var, which is limited to method variables.
Further, you can't change the signature in C# (adding a public getter in the subclass) - you would have to re-declare it:
// base type
protected string Foo {get;set;}
// derived type
new public string Foo {
get { return base.Foo; }
protected set { base.Foo = value; }
}
But as the new suggests: this is an unrelated property and is not required to have the same type.
As far as I understand you can do like this:
public class Parent
{
protected Int64 MyCounter{ get; set; }
}
public class Child : Parent
{
protected string ClassName
{
get
{
return "Child";
}
}
}
public class Runner
{
static void Main(string[] args)
{
var c = new Child();
c.Counter++;
Console.WriteLIne(c.Counter);
}
}