-1

I made project Animal and set it as Library. Of course in Animal project I'll add more classes. In this project I have 2 classes for now: Dog and Method.

//Class Method
public class Method : Attribute{
    public string Name { get; set; }
    public Method(){
        Name = "";
    }
}

//Class Dog
[Method(Name = "dog")]
public class Dog
{
    public int NumberOfLegs { get; set; }
    public string Breed { get; set; }
    public Dog() { }
}

Then I created second project in my solution Ref and it is my main class:

//version 1
class Program{
    public static Dictionary<String, Type> animals;
    static void Main(string[] args){
        Assembly assembly = Assembly.GetEntryAssembly();
        Type[] typ = assembly.GetTypes();
        foreach (Type t in typ){
            animals.Add(t.Name, t);
        }
    }
}

I want achieve "dog, Dog", "cat, Cat", "rat, Rat". Where "dog" is name attribute and "Dog" is a type thanks to I will be able to make something like

Activator.CreateInstance(animals[nameAnimal]);

But for now I do something wrong, my way doesn't work and I cannot find working solution for my problem in .net core. I want only object from classes where is Attribute Method. How achieve it?

EDIT. My program don't see library "Dog" and search for "Ref.*" libraries for example Ref, Ref.Program, etc.

nju
  • 53
  • 1
  • 9
  • *What* isn't working? – InBetween Jul 27 '17 at 08:40
  • Are you using Visual Studio? – Jonathan Willcock Jul 27 '17 at 08:48
  • @JonathanWillcock yes, 2017 – nju Jul 27 '17 at 08:50
  • are you aware how to extract type attributes? please look at this https://stackoverflow.com/questions/2656189/how-do-i-read-an-attribute-on-a-class-at-runtime – Roman Ananyev Jul 27 '17 at 08:53
  • Possible duplicate of [How do I read an attribute on a class at runtime?](https://stackoverflow.com/questions/2656189/how-do-i-read-an-attribute-on-a-class-at-runtime) – Roman Ananyev Jul 27 '17 at 08:56
  • @RomanAnanyev not really, this solution didn't work because in .Net core I have no access for some functions. Can you read whole my post before you write something? – nju Jul 27 '17 at 09:02
  • I think you need to right click on References in your second project and use Add references to point to the library in your first project. If they are both in the same solution, you can find it under Projects on the left hand side, otherwise you will need to browse for the compiled dll. For development purposes it is best to keep them both in one solution – Jonathan Willcock Jul 27 '17 at 09:06
  • possible my fault - but you can find the answer here https://stackoverflow.com/questions/12814723/what-is-an-equivalent-method-to-getcustomattributes-for-netcore-windows-8-fr and here https://stackoverflow.com/questions/43247759/system-attribute-getcustomattribute-in-net-core – Roman Ananyev Jul 27 '17 at 09:07
  • @JonathanWillcock I did it, but still don't work – nju Jul 27 '17 at 09:23
  • Have you checked the namespaces? – Jonathan Willcock Jul 27 '17 at 09:24
  • @JonathanWillcock of course, I did even new project and use your solutions – nju Jul 27 '17 at 09:28

5 Answers5

0

Quite a few issues in your code:

  1. You a have a NullReferenceException in your code; animals is null.
  2. Why are you implementing attributes that you are not using at all?

    You are storing all the types in your assembly assembly.GetTypes(); and you only want to store types that define your attribute Method.

    Also, t.Name is not the property of your attribute, its the name of the type; Type.Name.

    What you probably want is:

    var allTypes = assembly.GetTypes();
    
    foreach (var t in allTypes)
    {
        var methodAttribute = t.GetCustomAttribute<Method>();
        if (methodAttribute != null } animals.Add(methodAttribute.Name, t);
    }
    
  3. Method should have a constructor with one argument, your code is needlessly complicated:

    public Method(string name)
    {
        Name = name;
    }
    

    And Name should be read only:

    public string Name { get; }
    
  4. Use the naming conventions. Attributes should have the Attribute suffix:

    public class MethodAttribute { ... }
    

    The compiler will do some of its magic and allow you to use the "short" name anyhow:

    [Method("Dog")]
    public class Dog { ... }
    
InBetween
  • 32,319
  • 3
  • 50
  • 90
  • @nju Thats weird. Do you have the proper namespace declared: `using System.Reflection`? That should make the extension methods provided by [`CustomAttributeExtensions.cs`](https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Reflection/CustomAttributeExtensions.cs) available. – InBetween Jul 27 '17 at 09:23
  • in my project t is a Type and does not contain this method. And yes, I have 'using System.Reflection' – nju Jul 27 '17 at 09:27
0

You can use the following peace of code..

Assembly assembly = Assembly.GetEntryAssembly();
        Type[] typ = assembly.GetTypes();

        foreach (Type t in typ)
        {
            IList<CustomAttributeData> m = t.GetCustomAttributesData();
            if(m.Count>0)
            animals.Add(t.Name, m[0].NamedArguments[0].TypedValue.Value.ToString());

        }
Koderzzzz
  • 849
  • 8
  • 18
0

Sorry for my earlier stupidity. I have just had a bit more time and read everything again. I now think I understand your problem. What you want to know is why using relection you do not see your other two classes? The reason for this is simple: these two classes are not in the same assembly! Your first project compiles to a dll. This is it's own assembly. Your second project compiles to a exe which is another assembly. Using reflection within the second assembly, therefore, only shows you the Types in the second assembly.

To get what you want, simply move your dog class from the library and include them in your second project. Then you will be able to see them in Main.

EDIT

Use this:

Assembly assembly = Assembly.ReflectionOnlyLoadFrom("yourlibname.dll"); 
Type[] typ = assembly.GetTypes();
foreach (Type t in typ)
{
    animals.Add(t.Name, t);
}

Assuming you compile the solution together then dll should be in the same bin folder as your exe. Otherwise you need to give full path.

Jonathan Willcock
  • 5,012
  • 3
  • 20
  • 31
  • Yes it is not bad solution but I have to keep it in different project(library). So I need to search this dll? – nju Jul 27 '17 at 10:21
  • Assembly does not contain ReflectionOnlyLoadFrom. I am using .net core – nju Jul 27 '17 at 10:57
0

Below is the complete program.

class Program
{
    public static Dictionary<String, string> animals = new Dictionary<string, string>();
    static void Main(string[] args)
    {


        Assembly assembly = Assembly.GetEntryAssembly();
        Type[] typ = assembly.GetTypes();

        foreach (Type t in typ)
        {
            IList<CustomAttributeData> m = t.GetCustomAttributesData();
            if(m.Count>0)
            animals.Add(t.Name, m[0].NamedArguments[0].TypedValue.Value.ToString());

        }


    }

}
public class Method : Attribute
{
    public string Name { get; set; }
    public Method()
    {
        Name = "";
    }
}

//Class Dog
[Method(Name = "dog")]
public class Dog
{
    public int NumberOfLegs { get; set; }
    public string Breed { get; set; }
    public Dog() { }
}   
Koderzzzz
  • 849
  • 8
  • 18
  • still line t.GetCustomAttributesData(); error - 'Type' does not contain a definition .... – nju Jul 27 '17 at 10:27
0

You can use CustomAttributes property of TypeInfo:

class Program
{
    public static Dictionary<string, Type> animals = new Dictionary<string, Type>();

    static void Main(string[] args)
    {
        Assembly assembly = Assembly.GetEntryAssembly();
        Type[] typ = assembly.GetTypes();
        foreach (Type t in typ)
        {
            // check if the type has attribute of Method type
            var attrData = t.GetTypeInfo().CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(Method));
            if(attrData==null || !attrData.NamedArguments.Any(x => string.Equals(x.MemberName, nameof(Method.Name)))) continue;

            animals.Add(attrData.NamedArguments[0].TypedValue.Value.ToString(), t);
        }
    }
}
Anton Semenov
  • 6,227
  • 5
  • 41
  • 69