EF Core 7 - Class / Member Attributes - c#

I have a class attribute which defines a value, then I have a Method attribute, which even defines a value.
Then I want to access the value of the class attribute from the method attribute.
[MyClassAttribute("SomethingClass")]
public class MyClass
{
[MyMethodAttribute("SomethingMethod")]
public void MyMethod() { }
}
Something like this should be done:
public class MyMethodAttribute : Attribute
{
public MyMethodAttribute(params string value)
{
var myClassAttributeValue = PARENTCLASS.MyClassAttributeValue;
var combined = myClassAttributeValue + value;
}
}
How to achieve that?

Related

C# Custom attributes passed down to called methods

Is there a way to get custom attributes which are added along the flow? I'm adding custom attributes to different methods in different classes that are called depending on the flow. I've tried MethodBase.GetCurrentMethod() but this (as it says) only the current invoked method. Using new StackFrame(n) also doesn't work since "n" can frequently change. Googled my problem but didn't find any hints.
public class CustomAttribute1 : Attribute
{
public bool Property { get; }
public CustomAttribute1(bool property) => Property = property;
}
public class CustomAttribute2 : Attribute
{
public string Property { get; }
public CustomAttribute2(string property) => Property = property;
}
public class GeneralService
{
protected void Resolve()
{
// Here I want to access custom attributes combined
}
}
public class SpecifiedService : GeneralService
{
[CustomAttribute1(true)]
public void SendRequest()
{
Resolve();
}
}
public class Worker
{
[CustomAttribute2("init")]
public void Init()
{
var service = new SpecifiedService();
service.SendRequest();
}
}

creating custom attribute with logic inside

I have this custom attribute here where it does some logics
[AttributeUsage(AttributeTargets.All)]
public class CustomAttribute : Attribute
{
public CustomAttribute ()
{
bool foo = false;
if (foo)
Console.WriteLine ("TRUE");
}
}
then i want to use it in my component class like this
[Custom]
public class Component
{
public void Test()
{
console.log("test");
}
}
so what i want is every time i created an instance of that component class, it will basically call or execute that code in my attribute to do some logic, but the problem is, it doesn't execute the code inside my custom attribute class. I know I'm doing it wrong, anyone has idea how to do it?
When the class is instantiated, it will not inherently call any code tied to your attribute, or even instantiate it. Attributes are only instantiated when you call them using reflection. If you would want the attributes to be processed when a class is constructed, you would have to call a method in a constructor on your Component class that uses reflection to analyze the attributes on your class.
The ideal approach would be instead to inherit from a base class that has constructor logic:
public class Component : CustomBase
{
public void Test()
{
console.log("test");
}
}
public abstract class CustomBase
{
public CustomBase()
{
bool foo = false;
if (foo)
Console.WriteLine ("TRUE");
}
}
You need to call:
object[] attributes = typeof(MyClass).GetCustomAttributes(true);
somewhere, because this is the code that triggers the attributes constructor to run.
You can make a method in your attribute class, that calls this line, and in your Component, call the attribute method.
As Jason and Cristina said , you need to take account of reflection to code with custom attributes. If you read the code below (from line 18 to 24) you can see some commented out code that list all the CustomAttributes associated with a type.
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomAttributeTest
{
class Program
{
static void Main(string[] args)
{
var customCompo = new Component();
customCompo.Test();
//System.Reflection.MemberInfo info = typeof(Component);
//object[] attributes = info.GetCustomAttributes(true);
//for (int i = 0; i < attributes.Length; i++)
//{
// System.Console.WriteLine(attributes[i]);
//}
Console.ReadLine();
}
}
[CustomAttribute(true)]
public class Component
{
public void Test()
{
System.Console.WriteLine("Component contructed");
var member = typeof(Component);
foreach (object attribute in member.GetCustomAttributes(true))
{
if (attribute is CustomAttribute)
{
//noop
}
}
}
}
[AttributeUsage(AttributeTargets.All)]
public class CustomAttribute : Attribute
{
private bool _value;
//this constructor specifes one unnamed argument to the attribute class
public CustomAttribute(bool value)
{
_value = value;
Console.WriteLine(this.ToString());
}
public override string ToString()
{
string value = "The boolean value stored is : " + _value;
return value;
}
}
}

Get class type in attribute class

I want to validate condition on class definition in the build process and show build error in case that something is not validated.
In the build process attribute instance is created for each class that defined by this attribute.
I want to check something like for example that the class does not have more than 4 properties(just for example, this is not my intention). How can I get the type from the attribute constructor for each class?
(Without passing it as parameter).
Example:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ValidatePropertiesAttribute:ValidationAttribute
{
public ValidatePropertiesAttribute()
{
if(Validate()==false)
{
throw new Exception("It's not valid!! add more properties to the type 'x'.");
}
}
public bool Validate()
{
//check if there are at least 4 properties in class "X"
//Q: How can I get class "X"?
}
}
[ValidateProperties()]
public class ExampleClass
{
public string OnOneProperty { get; set; }
}
Is it possbile?
If not, is there any other way to do it?
(add validation to the build process and show errors in case that something was not validated)
This solution may work
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ValidatePropertiesAttribute:ValidationAttribute
{
private Type TargetClass;
public ValidatePropertiesAttribute(Type targetClass)
{
TargetClass = targetClass;
if(Validate() == false)
{
throw new Exception("It's not valid!! add more properties to the type 'x'.");
}
}
public bool Validate()
{
//Use Target Class,
//if you need extract properties use TargetClass.GetProperties()...
//if you need create instance use Activator..
}
}
Use this attribute as follows
[ValidateProperties(typeof(ExampleClass))]
public class ExampleClass
{
public string OnOneProperty { get; set; }
}

Can I define a property which is available to both the class type and instances of the class?

I have an interface for a base class, and every class that inherits from the base class should have an identifying field which tells the application what kind of object it is.
I wanted to use this property in two different ways:
Without creating an instance of the object
if (someValue == TestA.Id)
return new TestA();
elseif (someValue == TestB.Id)
return new TestB();
And as a property of the interface
void DoSomething(ITest testObject)
{
SomeValue = testObject.Id;
}
Is there an easy way to define the Id field in the interface, but still have it available to use without creating an instance of the class?
Right now I am using the following code. I could add a read-only Id property to the interface which returns the const string, however I was hoping there was a simpler way that I'm just not aware of.
public interface ITest
{
}
public class TestA : ITest
{
public const string Id = "A";
}
In short - no.
In order to be able to do this, you'd need to be able to specify this as a instance property on the interface (and implement it in the instance), and as a static property on the type.
The compiler won't let you do this.
You can put it in the interface, and also have it as a static property. Something like:
interface IInterface { Id { get; } }
class Class : IInterface
{
public static Id { get { return 1; } }
public Id { get { return Class.Id; } }
}
I've faced a similar problem, Rachel, and I've always (unfortunately) resorted to having that factory code rely on reflection to get a "TypeID" public static property on each concrete type... thus making an additional aspect of the contractual interface, but not having it in the C# interface code.
You could do it this way.
public interface ITest
{
SomeValue Id{ get;}
}
public class TestA : ITest
{
public SomeValue Id
{
get {return TestA.StaicId; }
}
public static SomeValue StaticId
{
get {return "This is TestA";}
}
}
if (someValue == TestA.StaticId)
return new TestA();
How about using attributes? Here's a small example of what can be done:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class IdAttribute : Attribute
{
public IdAttribute(string id)
{
this.Id = id;
}
public string Id { get; set; }
}
public interface IMyInterface
{
}
public abstract class BaseClass : IMyInterface
{
public static string GetId<T>() where T : IMyInterface
{
return ((IdAttribute)typeof(T).GetCustomAttributes(typeof(IdAttribute), true)[0]).Id;
}
}
[Id("A")]
public class ImplA : BaseClass
{
}
[Id("B")]
public class ImplB : BaseClass
{
}
internal class Program
{
private static void Main(string[] args)
{
var val1 = BaseClass.GetId<ImplA>();
var val2 = BaseClass.GetId<ImplB>();
Console.ReadKey();
}
}

How to get the name of the class

Ok, I have the following structure. Basically a plugin architecture
// assembly 1 - Base Class which contains the contract
public class BaseEntity {
public string MyName() {
// figure out the name of the deriving class
// perhaps via reflection
}
}
// assembly 2 - contains plugins based on the Base Class
public class BlueEntity : BaseEntity {}
public class YellowEntity : BaseEntity {}
public class GreenEntity : BaseEntity {}
// main console app
List<BaseEntity> plugins = Factory.GetMePluginList();
foreach (BaseEntity be in plugins) {
Console.WriteLine(be.MyName);
}
I'd like the statement
be.MyName
to tell me whether the object is BlueEntity, YellowEntity or GreenEntity. The important thing is that the MyName property should be in the base class, because I don't want to reimplement the property in every plugin.
Is this possible in C#?
I think you can do it through GetType:
public class BaseEntity {
public string MyName() {
return this.GetType().Name
}
}
public class BaseEntity {
public string MyName() {
return this.GetType().Name;
}
}
"this" will point to the derived class, so if you were to do:
BaseEntity.MyName
"BaseEntity"
BlueEntitiy.MyName
"BlueEntity"
EDIT: Doh, Gorky beat me to it.
C# implemented a way to look at objects called Reflection. This can return information about the object you are using.
The GetType() function returns the name of the class you are calling it on. You can use it like this:
return MyObject.GetType().Name;
Reflection can do a lot of things. If there is more that you want to know about reflection you can read about it on these websites:
MSDN Reflection Article
Oreilly Chapter
Code Source Tutorial
Change your foreach statement to the following
foreach (BaseEntity be in plugins) {
Console.WriteLine(be.GetType().Name);
}
If you haven't overridden the ToString() method for the class, then you can just write the following
string s = ToString().Split(',')[0]; // to get fully qualified class name... or,
s = s.Substring(s.LastIndexOf(".")+1); // to get just the actual class name itself
using yr code:
// assembly 1 - Base Class which contains the contractpublic class BaseEntity
{
public virtual string MyName // I changed to a property
{
get { return MyFullyQualifiedName.Substring(
MyFullyQualifiedName.LastIndexOf(".")+1); }
}
public virtual string MyFullyQualifiedName // I changed to a property
{
get { return ToString().Split(',')[0]; }
}
}
// assembly 2 - contains plugins based on the Base Class
public class BlueEntity : BaseEntity {}
public class YellowEntity : BaseEntity {}
public class GreenEntity : BaseEntity {}
// main console app
List<BaseEntity> plugins = Factory.GetMePluginList();
foreach (BaseEntity be in plugins)
{ Console.WriteLine(be.MyName);}
Try this pattern
class BaseEntity {
private readonly m_name as string;
public Name { get { return m_name; } }
protected BaseEntity(name as string) {
m_name = name;
}
}
class BlueEntity : BaseEntity {
public BlueEntity() : base(typeof(BlueEntity).Name) {}
}

Categories