Get attribute information from inheriting class, inside static function - c#

I have a situation where I need to get the value on a property on an attribute (decorator) applied to a class. That class that is decorated, is inheriting from an abstract class. It is this abstract class that needs to get the attribute information, but it needs to do so inside a static function.
I cannot post the exact scenario, but here is a terrible example that could do without attributes, but please work with it as it is:
public class VehicleShapeAttribute : Attribute
{
public string Shape { get; }
public VehicleShapeAttribute(string shape)
{
Shape = shape;
}
}
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public static string GetVehicleShape()
{
//return value from the attribute, from this static function. CANT DO THIS HERE
return AnyInheritingClass.VehicleShapeAttribute.Shape;
}
}
[VehicleShape("sedan")]
public class VauxhaulAstraSedan : Vehicle
{
//calling GetVehicleShape() on this class should automatically return "sedan"
}
Is this possible?
This is a bad example but I cannot post the actual code

Make the method non-static and resolve the runtime type with this.GetType():
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public string GetVehicleShape()
{
var attribute = Attribute.GetCustomAttribute(this.GetType(), typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
}
For a static version, you'll need to accept a Vehicle parameter whose type you can then inspect:
public static string GetVehicleShape(Vehicle vehicle)
{
var attribute = Attribute.GetCustomAttribute(vehicle.GetType());
// ...

Alternatively (and I'm just copy/pasting Mathias' code into another form syntactically here) if you really need to have the method static because you don't want to create an instance, you can add the following method to your attribute code (or any other static class, but I like to put it there with the attribute):
public static string GetFrom<T>()
{
return GetFrom(typeof(T));
}
public static string GetFrom(Type t)
{
var attribute = Attribute.GetCustomAttribute(t, typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
Then you could write code like:
var shape = VehicleShapeAttribute.GetFrom<VauxhaulAstraSedan>();
or
var shape = VehicleShapeAttribute.GetFrom(typeof(VauxhaulAstraSedan));
or even
var vehicle = new VauxhaulAstraSedan();
var shape = VehicleShapeAttribute.GetFrom(vehicle.GetType());

Related

How to get members of abstract class using reflection?

I have following:
var type = typeof(ExampleClass);
public abstract class ExampleClass
{
public string Name { get; set; }
public abstract class InternalExampleClass
{
public string InternalName { get; set; }
}
}
How can I get the value of Name, InternalName?
I tried to use type.GetFields() but it doesn't return InternalName
help me, please
I can't answer all points of your question. But I can give you an idea how to start.
You don't have access to constants, but there is a workaround. First, you need an instance of your abstract class in order to use reflection. Since you can't create an object of an abstract class, you need a class which inherits it. This class contains properties set to the value of your constants.
public class InheritedReportAPI : ReportAPI
{
public string constName { get; } = ReportAPI.Name;
public string constSignatureBase { get; } = ReportAPI.SignatureBase;
public string constEventsReportsDeleted { get; } = ReportAPI.Events.ReportsDeleted;
}
Then you can use Reflection to get names and/or values of these properties.
var inheritedReportApi = new InheritedReportAPI();
var propertyList = inheritedReportApi.GetType().GetProperties();
foreach(var property in propertyList)
System.Console.WriteLine($"{property.Name}: {property.GetValue(inheritedReportApi)}");
The result:
constName: reports
constSignatureBase: /report/reports
constEventsReportsDeleted: reports_deleted

C# - CS0572 Error When Trying to Populate a Class

C# Newbie Here.
I have a class below:
namespace CompanyDevice.DeviceResponseClasses
{
public class DeviceStatusClass
{
public class Root
{
public static string RequestCommand { get; set; }
}
}
}
In another namespace I have:
namespace CompanyDevice
{
public class StatusController : ApiController
{
public DeviceStatusClass Get()
{
var returnStatus = new DeviceStatusClass();
returnStatus.Root.RequestCommand = "Hello"; //'Root' is causing a CS0572 error
return returnStatus;
}
}
}
I'm sure I'm making some rudimentary error here. Could you please help me find it? Thanks.
You access static properties from the type, not from the instance.
DeviceStatusClass.Root.RequestCommand = "Command";
Because the property RequestCommand is static, there will only ever be one. Perhaps this is what you want, but likely is not based on your usage.
You can remove the static keyword from RequestCommand, then you can access it through the instance, however you will need to add a field or property for the instance of Root inside of DeviceStatusClass.
public class DeviceStatusClass
{
public Root root = new Root();
public class Root
{
public string RequestCommand { get; set; }
}
}
And use like you did originally.
public class StatusController : ApiController
{
public DeviceStatusClass Get()
{
var returnStatus = new DeviceStatusClass();
returnStatus.root.RequestCommand = "Hello";
return returnStatus;
}
}
You maybe have a java background. In c# nested classes only change the names, they do not make the parent class contain an instance of a child class
namespace CompanyDevice.DeviceResponseClasses
{
public class DeviceStatusClass
{
public class Root
{
public static string RequestCommand { get; set; }
}
public Root DeviceRoot {get;set;} <<<=== add this
}
}
and then
returnStatus.DeviceRoot.RequestCommand = "Hello";

Instantiate any one of several derived classes (depending on an argument) within a static method of the abstract base class

I have been trying to find an elegant way to avoid repeating code in all of my derived classes. At this point, I am unsure as to the best way to proceed.
I'd like to write a single method in the base class that will instantiate and use any of its derived classes without having to edit the method when I write new derived classes.
I have tried learning/using a generic method but started to think I might be heading down a dead end for this application. I understand that using reflection can be expensive, and since this method is meant to handle hundreds or even thousands of Elements, it seemed like a bad idea.
Now I'm thinking of trying to pass in the class itself as an argument somehow... maybe. That doesn't seem quite right to me either.
I'm willing to do the research, but would love any help pointing me in the right direction.
Here is an abridged version of what I have...
Base Class:
public abstract class Element
{
public string ElementName { get; }
public List<string> BadParameters { get; set; } = new List<string>();
//Constructor
public Element(string name)
{
ElementName = name;
}
//The method in question---
public static List<string> GetBadParameters(//derived class to instantiate)
{
var elem = new //derived class();
return elem.BadParameters;
}
}
Derived Class 1:
public class Wall : Element
{
public double Length { get; set; }
public bool LoadBearing { get; set; }
//Constructor
public Wall(string name): base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = //A wall specific way of setting bad parameters
}
}
Derived Class 2:
public class Floor : Element
{
public double Area { get; set; }
public double Slope { get; set; }
//Constructor
public Floor(string name): base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = //A floor specific way of setting bad parameters
}
}
Implementation:
public class Implementation
{
public List<string> GetAllBadElementParameters()
{
List<string> output = new List<string>;
List<string> badWalls = GetBadParameters(//Wall class)
List<string> badFloors = GetBadParameters(//Floor class)
output = output.AddRange(badWalls).AddRange(badFloors);
return output;
}
}
EDIT - To clarify:
The actual content of
public List<string> BadParameters
does not matter. Bad parameters, how and why they are bad, are inconsequential.
What I'm trying to accomplish is avoid having the method "GetBadParameters()" defined in the derived class, since this method will be the exact same for all derived classes.
It is only the populating of the "BadParameter" base class property that changes from one derived class to another.
EDIT 2 - My attempt at a generic method in the base class:
I know this won't work, but it may convey what I'd like to have happen.
public static List<string> GetAllBadParameters<T>(List<string> names) where T : ANY DERIVED CLASS, new()
{
List<string> output = new List<string>();
foreach (string name in names)
{
var elem = new T(name);
foreach (string badParameter in elem.BadParameters)
{
output.Add(badParameter);
}
}
return output;
}
Well … First of all, I am guessing that by "bad parameter" you mean the name of a property in an Element-derived class. For example I'm guessing that if the Length of a Wall is negative then "Length" would be a bad parameter of that particular Wall. Secondly I'm guessing that you are going to have a largish number of elements, e.g. a number of walls and floors (and other things) in a diagram or whatever.
Assuming that, then one way to do this would be to have an abstract method in the Element class that returns the bad parameters, and implement it in each derived class. Something like this:
public abstract class Element
{
public string Name { get; private set; }
public abstract IList<string> GetBadParameters();
public Element( string name) { this.Name = name; }
}
public class Wall
{
public Wall( string name): base(name) {}
public double Length { get; set; }
public bool IsLoadBearing { get; set; }
public IList<string> GetBadParameters() {
List<string> bad = new List<string>();
if (this.Length <= 0) { bad.Add( this.Name + ": " + nameof( this.Length); }
if (this.IsLoadBearing && this.Length > whatever) { bad.Add( this.Name + ": " + nameof( this.IsLoadBearing); }
return bad;
}
}
Then if you had a list of all the elements you could get all the bad parameters by
IList<string> allBadParemeters = elements.SelectMany( e => e.GetBadParameters() );
What I would say though is that this might not be such a great design. You would end up with a system in which a lot of elements contain bad parameters. Life could be a lot easier if you just prevent bad parameters from happening in the first place. You can do this by making the 'set' methods of all the parameter properties private and adding a method such as bool Wall.TrySetParameters( double length, bool isLoadBearing). If the parameters are bad then this would just return false and not assign the parameters to the wall. If you want to have TrySetParameters in the base class then you could do it with a more general signature such as
public struct Parameter {
public Parameter( string name, object value) { … }
public string Name { get; private set; }
public object Value { get; private set; }
}
abstract public class Element {
…
abstract public bool TrySetParameters( params Parameter[] parameters);
}
I am assuming your BadParameter list content is same for all derived Classes. If this list is not common then there is no point in filling these list in Base Class.
By that assumption I can suggest you following changes .
Your base class looks like this . There is no need of making GetBadParameters() as static
public abstract class Element
{
public string ElementName { get; }
public List<string> BadParameters { get; set; } = new List<string>();
//Constructor
public Element(string name)
{
ElementName = name;
}
/// <summary>
/// Tjis Method is common for alal derived classes. Assuming content is same for all dervied class
/// </summary>
/// <returns></returns>
//The method in question---
public List<string> GetBadParameters()
{
return new List<string>() { "1", "2" };
}
}
Your first derived class Wall, where it will call GetBadParameters from base .
public class Wall : Element
{
public double Length { get; set; }
public bool LoadBearing { get; set; }
//Constructor
public Wall(string name) : base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = GetBadParameters();//Calling base GetBadParameters
}
}
Same goes with second derived class "Floor"
public class Floor : Element
{
public double Area { get; set; }
public double Slope { get; set; }
//Constructor
public Floor(string name) : base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = GetBadParameters();//Calling base GetBadParameters
}
}
In your implementation class, you can create both wall and floor objects by keeping Element class as reference and call respective GetBadParameters
public class Implementation
{
public List<string> GetAllBadElements()
{
List<string> output = new List<string>;
Element _wall = new Wall("wall");
Element _floor = new Floor("floor");
List<string> badWalls = _wall.GetBadParameters(); //Returns Wall bad Parameters
List<string> badFloors = _floor.GetBadParameters(); //Returns Floor bad Parameters
output = output.AddRange(badWalls).AddRange(badFloors);
return output;
}
}

Need solution regarding generic c# method

I am trying to make my method generic and I am stuck at a point and need your assistance. The code scenario is I have an abstract class say MyBaseAbs which contains common properties:
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
}
Now I have child classes:
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
}
and another child class:
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
}
Now I have to create a common method which needs to perform some operations on the basis of Mychild1 and Mychild2, so what I did is:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
}
so inside this method I need to write common code which does the mapping for SaveObject object according to the child object passed. How can I determine which object is passed and use properties accordingly.
One option would be to create a base Save function in your base class and make it virtual.
Then override the method in your child classes. This way when you call the Save method in your SaveOperation it should call the appropriate method from the correct child class.
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
public virtual void Save() { }
}
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
public override void Save() {
//Implementation for Mychild1
}
}
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
public override void Save() {
//Implementation for Mychild2
}
}
If you can't modify your business objects, you can check the type of the concrete class in the SaveOperation method:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
if (myObj is Mychild1) {
Mychild1 mychild1 = (Mychild1) myObj;
// Business logic for object of type Mychild1
} else if (myObje is Mychild2) {
Mychild2 mychild2 = (Mychild2) myObj;
// Business logic for object of type Mychild2
}
}
Notice that this is not a very solid solution as, if you are creating new objects that implement your abstract class, you will have to remeber to add another branch in the if statement.
As #BojanB mentioned, the obvious solution would be to create a virtual method in your base class and override it in the derived, but if you cannot modify the code there then you can create a method for each derived class and create a dictionary that maps each type to its method:
private Dictionary<Type, Action<MyBaseAbs, MyCustomClass>> _saveOperations =
new Dictionary<Type, Action<MyBaseAbs, MyCustomClass>>();
//You can then set an entry for each of your derived classes
_saveOperations[typeof(Mychild1)] = (myObj, myCustomObj) =>
{
//Mychild1-specific logic
};
public MyCustomClass SaveOperation(MyBaseAbs obj)
{
//do the common saving operations here
var result = new MyCustomClass();
//....
var actualType = obj.GetType();
if(_saveOperations.ContainsKey(actualType))
{
_saveOperations[actualType](obj, result);
}
return result;
}
You can then add an item to the dictionary for each derived class. It is the same concept as using the is operator but allows you to add methods for more derived types without modifying the original SaveOperation method
You can use C#'s As-Operator as follows:
Mychild1 child1 = myObj as Mychild1;
if(child1 != null) {
//Here you can use child1.Mychild1Prop1 forexample
}
Link to msdn: https://msdn.microsoft.com/en-us/library/cscsdfbt.aspx

Make generic object instantiation more generic

I've got this piece of code to create new objects in a generic way:
var user = User.Create<User>(c => c.Name = "321X");
What I don't like about it is the fact I need to pass the 'generic notation' <T> for every create call. After all I create an object that I'm already referring to...
The code behind this current functionality is:
public class User : CreateBase
{
public string Name { get; set; }
}
public abstract class CreateBase
{
public DateTime CreateDate { get; set; }
public Guid Guid { get; set; }
public static T Create<T>(Action<T> init) where T : CreateBase, new()
{
T obj = new T();
obj.Guid = Guid.NewGuid();
obj.DateTime = DateTime.Now;
init(obj);
return obj;
}
}
Is it possible (and how) to refactor my code to this, to create an object?
var user = User.Create(c => c.Name = "321X");
Thanks!
Define the generic argument on the class level:
public abstract class CreateBase<T> where T : CreateBase<T> , new()
{
public static T Create(Action<T> init)
{
//...
}
}
public class User : CreateBase<User>
{
public string Name { get; set; }
}
Then you can write var user = User.Create(c => c.Name = "321X");
Otherwise the compiler cannot infer the type for your Create method without specifying the type argument.
You were not very far. Try this modification:
public abstract class CreateBase<T> where T : CreateBase<T> , new()
{
public DateTime CreateDate { get; set; }
public Guid Guid { get; set; }
public static T Create(Action<T> init)
{
T obj = new T();
obj.Guid = Guid.NewGuid();
obj.CreateDate = DateTime.Now;
init(obj);
return obj;
}
}
public class User : CreateBase<User>
{
public string Name { get; set; }
}
EDIT: Updated the code after I tested it on my local environment. It works now.
You are doing it the wrong way. Instead of getting rid of the generic argument, get rid of (needlessly) saying User.. Instead:
CreateBase.Create<User>(...)
No more redundancies.
Besides that, calling a static member of the base class through a derived class is an anti-pattern.
A better approach would be to include this functionality in the constructor of the base class (I call it ModelBase)
public abstract class ModelBase
{
public DateTime CreateDate { get; private set; }
public Guid Guid { get; private set; }
public ModelBase()
{
Guid = Guid.NewGuid();
DateTime = DateTime.Now;
}
}
public User : ModelBase
{
public User()
: base()
{
}
public User(string name)
: base()
{
Name = name
}
public string Name { get; set; }
}
Creating a user the standard way will initialize the Guid and date automatically
var user = new User { Name = "xy };
EDIT
I added a second constructor with a name parameter. I you want to force the initialization of the name, drop the first parameterless constructor.
var user = new User("xy");
If you really uncomfortable with that sintax (I, honestly, don't see much problem here)
you can do the following:
public class User : CreateBase
{
public string Name { get; set; }
public static User Create(Action<User> a)
{
return Create<User>(a); //CALL BASE CLASS GENERIC FUNCTION
}
}
After you can call it in a way you would like to do that :
var user = User.Create(c => c.Name = "321X");

Categories

Resources