Here is my code:
[AttributeUsage(AttributeTargets.Method)]
public class WorkAttribute : System.Attribute
{
public string Message;
public WorkAttribute(string message)
{
this.Message = message;
}
}
[Work("WorkMessage")]
public void test(){...}
foreach (MethodInfo methodInfo in type.GetMethods())// type is the class's type
{
WorkAttribute workAttribute = methodInfo.GetCustomAttribute<WorkAttribute>();
if (workAttribute != null)
{
Console.WriteLine(workAttribute.Message);// Should print "WorkMessage", but Message is null.
}
}
When I set a break point at the WorkAttribute's constructor, I can see the message past in correctly. But after I call GetCustomAttribute, all the fields inside WorkAttribute is null.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
[AttributeUsage(AttributeTargets.Method)]
public class WorkAttribute : System.Attribute
{
public string Message;
public WorkAttribute(string message)
{
this.Message = message;
}
}
class Program
{
[Work("WorkMessage")]
public void test()
{
}
static void Main()
{
foreach (MethodInfo methodInfo in typeof(Program).GetMethods())
{
WorkAttribute workAttribute = methodInfo.GetCustomAttribute<WorkAttribute>();
if (workAttribute != null)
{
Console.WriteLine(workAttribute.Message);// Should print "WorkMessage", but Message is null.
}
Console.ReadLine();
}
}
}
}
This code prints "WorkMessage" just fine. Compare your non-posted code. You may be using the wrong method or wrong type or set the Message somewhere else.
Related
Is there a way for me to access a C# class attribute?
For instance, if I have the following class:
...
[TableName("my_table_name")]
public class MyClass
{
...
}
Can I do something like:
MyClass.Attribute.TableName => my_table_name
Thanks!
You can use Attribute.GetCustomAttribute method for that:
var tableNameAttribute = (TableNameAttribute)Attribute.GetCustomAttribute(
typeof(MyClass), typeof(TableNameAttribute), true);
However this is too verbose for my taste, and you can really make your life much easier by the following little extension method:
public static class AttributeUtils
{
public static TAttribute GetAttribute<TAttribute>(this Type type, bool inherit = true) where TAttribute : Attribute
{
return (TAttribute)Attribute.GetCustomAttribute(type, typeof(TAttribute), inherit);
}
}
so you can use simply
var tableNameAttribute = typeof(MyClass).GetAttribute<TableNameAttribute>();
You can use reflection to get it. Here's is a complete encompassing example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
public class TableNameAttribute : Attribute
{
public TableNameAttribute(string tableName)
{
this.TableName = tableName;
}
public string TableName { get; set; }
}
[TableName("my_table_name")]
public class SomePoco
{
public string FirstName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var classInstance = new SomePoco() { FirstName = "Bob" };
var tableNameAttribute = classInstance.GetType().GetCustomAttributes(true).Where(a => a.GetType() == typeof(TableNameAttribute)).Select(a =>
{
return a as TableNameAttribute;
}).FirstOrDefault();
Console.WriteLine(tableNameAttribute != null ? tableNameAttribute.TableName : "null");
Console.ReadKey(true);
}
}
}
Here's an extension that will make it easier, by extending object to give you an attribute helper.
namespace System
{
public static class ReflectionExtensions
{
public static T GetAttribute<T>(this object classInstance) where T : class
{
return ReflectionExtensions.GetAttribute<T>(classInstance, true);
}
public static T GetAttribute<T>(this object classInstance, bool includeInheritedAttributes) where T : class
{
if (classInstance == null)
return null;
Type t = classInstance.GetType();
object attr = t.GetCustomAttributes(includeInheritedAttributes).Where(a => a.GetType() == typeof(T)).FirstOrDefault();
return attr as T;
}
}
}
This would turn my previous answer into:
class Program
{
static void Main(string[] args)
{
var classInstance = new SomePoco() { FirstName = "Bob" };
var tableNameAttribute = classInstance.GetAttribute<TableNameAttribute>();
Console.WriteLine(tableNameAttribute != null ? tableNameAttribute.TableName : "null");
Console.ReadKey(true);
}
}
Attempting to make a protected internal member of a protected internal class within a public class results with the following issue:
Inconsistent accessibility: field type
'what.Class1.ProtectedInternalClass' is less accessible than field
'what.Class1.SomeDataProvider.data'
The accessibility should be equivalent, as far as I know.
Where am I mistaken?
Origination class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace what
{
public class Class1
{
// This class cannot be modified, is only
// here to produce a complete example.
public class PublicClass
{
public PublicClass() { }
}
protected internal class ProtectedInternalClass : PublicClass
{
public ProtectedInternalClass() { }
public void SomeExtraFunction() { }
}
public class SomeDataProvider
{
public int AnInterestingValue;
public int AnotherInterestingValue;
protected internal ProtectedInternalClass data; //<--- Occurs here.
public PublicClass Data { get { return data; } }
}
public static SomeDataProvider RetrieveProvider()
{
SomeDataProvider provider = new SomeDataProvider();
provider.data = new ProtectedInternalClass();
provider.data.SomeExtraFunction();
return provider;
}
}
}
Verifying protected and internal properties, same assembly:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace what
{
public class Class2 : Class1
{
public Class2()
{
var pi = new ProtectedInternalClass();
var provider = new SomeDataProvider();
provider.data = pi;
}
// no errors here
}
public class Class3
{
public Class3()
{
var pi = new Class1.ProtectedInternalClass();
var provider = new Class1.SomeDataProvider();
provider.data = pi;
}
// no errors here
}
}
Verifying protected and internal properties, different assembly:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace some_other_assembly
{
public class Class4 : what.Class1
{
public Class4()
{
var pi = new ProtectedInternalClass();
var provider = new SomeDataProvider();
provider.data = pi;
}
// no errors here
}
public class Class5
{
public Class5()
{
var pi = new what.Class1.ProtectedInternalClass(); // <--- Inaccessible due to protection level, as it should be.
var provider = new what.Class1.SomeDataProvider();
provider.data = pi; // <--- Intellisense implies inaccessible, but not indicated via error.
}
}
}
The protected applies to different classes, and this can be seen with
class Derived : what.Class1.SomeDataProvider // note: Derived is not a nested class
{
public void f()
{
var data = this.data;
}
}
in a different assembly.
this.data has to be accessible, since the class derives from SomeDataProvider. Its type, ProtectedInternalClass, is not accessible, since the class does not derive from Class1.
I am trying to make an instance of a class based on a string that will be retrieved from the User Interface, and then I want to access the properties of the instance of the class.
Here is an overview of what I have so far -
namespace MamdaAdapter
{
public interface IExchange
{
string GetTransport();
}
}
namespace MamdaAdapter
{
public class Exchange
{
public class Arca : IExchange
{
private const string _Transport = "tportname";
public string GetTransport()
{
return _Transport;
}
}
public static IExchange DeriveExchange(string ExchangeName)
{
IExchange SelectedExchange = (IExchange)Activator.CreateInstance(Type.GetType(ExchangeName));
return SelectedExchange;
}
}
}
namespace MyUserInterface
{
public class MainForm
{
private void simpleButton1_Click(object sender, EventArgs e)
{
IExchange SelectedExchange = Exchange.DeriveExchange("Exchange.Arca");
Console.WriteLine(SelectedExchange.GetTransport());
}
}
}
UPDATE:
Right now, I'm getting an Exception that says the "Value cannot be null" which to me means that it is unable to create the instance of the class given the string provided -
The problem here is how you specify the name of your class:
First, specify the namespace. Second, since Arca is an inner class you must use '+' instead of '.'
(...) = Exchange.DeriveExchange("MamdaAdapter.Exchange+Arca");
Assuming you UI doesnt expose the full type name, you typically want a dictionary to associate the display name to the type:
Dictionary<string, Type> _associations = new Dictionary<string, Type>();
Then, you simply instantiate the new object:
if(_associations.ContainsKey(someString))
{
Type selectedType = _associations[someString];
return Activator.CreateInstance(selectedType) as IExchange;
}
throw new ApplicationException("No type defined for that string yo");
If the string is not known at compile time, you basically need to check for the existance of the type:
var type = Type.GetType(someString);
if(type != null)
{
// Do Stuff
}
I wrote a small c# console application to simulate your need, tested ok, hope it helps:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MamdaAdapter;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
IExchange SelectedExchange = Exchange.DeriveExchange("MamdaAdapter.Arca");
Console.WriteLine(SelectedExchange.GetTransport());
}
}
}
namespace MamdaAdapter
{
public interface IExchange
{
string GetTransport();
}
}
namespace MamdaAdapter
{
public class Arca : IExchange
{
private const string _Transport = "tportname";
public string GetTransport()
{
return _Transport;
}
}
}
namespace MamdaAdapter
{
public class Exchange
{
public static IExchange DeriveExchange(string ExchangeName)
{
IExchange SelectedExchange = (IExchange)Assembly.GetAssembly(typeof(IExchange)).CreateInstance(ExchangeName, false, BindingFlags.CreateInstance, null, null, null, null);
return SelectedExchange;
}
}
}
If the Type you are looking for is not defined in the same assembly that is executing Type.GetType you must use the AssemblyQualifiedName (something like MyNamespace.MyClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089), even the FullName is not enough. Otherwise you could first get the assembly containing the class and then execute the GetType method of the Assembly class.
I have such work to(lab) do:
... information about events must e written in some files, which must be determinated by attached to this class attribute.
Wgat a sense is in this attribute? what it must to do?
All lab is "Write generic class of list with opportunity to generate events when you call some class methods. Information about events must e written in some files, which must be determinated by attached to this class attribute.
I don't understand reason of using in this lab attribute, please help me.
Here I have written sample generic class of list
Here are two files:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lab7
{
public class MyListClass<T>: IEnumerable<T>
{
public delegate void MyDelegate();
public event MyDelegate AddEvent;
public event MyDelegate RemEvent;
List<T> list;
public T this[int index]
{
get { return list[index]; }
set { list[index] = value; }
}
public void Add(T item)
{
list.Add(item);
if (AddEvent != null)
AddEvent();
}
public void Remove(T item)
{
list.Remove(item);
if (RemEvent != null)
RemEvent();
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
if (RemEvent != null)
RemEvent();
}
public MyListClass()
{
list = new List<T>();
}
public MyListClass(List<T> list)
{
this.list = list;
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
#region Events
/*static void AddHandler()
{
Console.WriteLine("Объект добавлен в коллекцию");
}
static void RemoveHandler()
{
Console.WriteLine("Объект удалён из коллекции");
}*/
#endregion
}
}
and here is main class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lab7
{
class Program
{
static void Main(string[] args)
{
MyListClass<int> lst = new MyListClass<int>();
lst.AddEvent +=new MyListClass<int>.MyDelegate(AddHandler);
lst.RemEvent+=new MyListClass<int>.MyDelegate(RemoveHandler);
lst.Add(2542);
lst.Add(785);
lst.RemoveAt(1);
}
static void AddHandler()
{
Console.WriteLine("Объект добавлен в коллекцию");
}
static void RemoveHandler()
{
Console.WriteLine("Объект удалён из коллекции коллекцию");
}
}
}
Sorry for my bad English. I don't say to do all lab for me, only give me ideas, and examples how to write this)
The question is difficult to understand, but I think it wants you do decorate your class or methods with an attribute which points to a file in which some sort of event data is stored.
So it would look something like this:
class SomeClass
{
[MyEventInfoAttribute(EventFile = "c:\\blah\\events.foo")]
void SomeMethod()
{
}
}
So you need to define an attribute:
public class MyEventInfoAttribute : Attribute
{
public property string EventFile { get; set; }
}
How you store the event information and implement the events is up to you.
Your code would have to use reflection to discover the attribute on the methods.
For example:
class SomeClass
{
[MyEventInfoAttribute(EventFile = "c:\\blah\\events.foo")]
void SomeMethod()
{
Type type = typeof(SomeClass);
MethodInfo method = type.GetMethod("SomeMethod");
object[] atts = method.GetCustomAttributes();
if (atts.Length > 0)
{
if (atts[0] is MyEventInfoAttribute)
{
string fileName = ((MyEventInfoAttribute)atts[0]).EventFile;
... now open the file, read the event info, and use it ...
}
}
}
}
This is a simplified example to give you an idea of the direction to go in.
I have the following class structure:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
namespace contractsTest
{
class Program
{
static void Main(string[] args)
{
IService s = new Service();
s.sendMessage(MessagesCreator.TestMessage);
}
}
class Service : IService
{
public void DoSomething(Message m)
{
}
}
static class MessageNames
{
public static string TestMessage
{
get
{
Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result<string>()));
return "TestMessage";
}
}
}
class Message
{
public Message(string _name)
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
Contract.Ensures(this.Name == _name);
this.Name = _name;
}
public string Name { get; private set; }
}
static class MessagesCreator
{
public static Message TestMessage
{
get
{
Contract.Ensures(Contract.Result<Message>() != null);
Contract.Ensures(Contract.Result<Message>().Name == MessageNames.TestMessage);
return new Message(MessageNames.TestMessage);
}
}
}
static class Extensions
{
public static void sendMessage(this IService service, Message m)
{
Contract.Requires<ArgumentNullException>(service != null);
Contract.Requires<ArgumentNullException>(m != null);
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(m.Name));
service.DoSomething(m);
}
}
[ContractClass(typeof(IServiceContract))]
interface IService
{
void DoSomething(Message m);
}
[ContractClassFor(typeof(IService))]
abstract class IServiceContract : IService
{
public void DoSomething(Message m)
{
Contract.Requires<ArgumentNullException>(m != null);
Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(m.Name));
// Do Something
}
}
}
In Main i get the following Warning CodeContracts: requires unproven: !string.IsNullOrWhiteSpace(m.Name)
Any idea how to fix it?
If I change main to:
static void Main(string[] args)
{
IService s = new Service();
Message messagesCreatorTestMessage = MessagesCreator.TestMessage;
if (string.IsNullOrWhiteSpace(messagesCreatorTestMessage.Name))
throw new InvalidOperationException();
s.sendMessage(messagesCreatorTestMessage);
}
the warning disappears, but there should be other more elegant ways of doing this.
The Ensures in the Message constructor only specifies that the condition will be true when the constructor finishes; it does not indicate that the condition will be true for the life of the Message instance.
To do this, use the Contract.Invariant method:
class Message
{
[ContractInvariantMethod]
private void MessageInvariants()
{
Contract.Invariant(!string.IsNullOrWhiteSpace(Name));
}
public Message(string _name)
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
Contract.Ensures(this.Name == _name);
this.Name = _name;
}
public string Name { get; private set; }
}
It's possible that this is the problem:
// In the Message constructor
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_componentName));
I suspect you mean:
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
It's not clear to me where _componentName even comes from...