Search code examples
c#adstwincat

Find variables with user defined attribute


In a c# app how would I find all the variables in a project with a specific Attribute?


class Program
{
    static void Main()
    {
        try
        {
            using (AdsClient Client = new AdsClient())

            {
                // Connect to the TwinCAT ADS router
                Client.Connect("172.18.233.27.1.1", 851);
                //Creating a symbol loader
                SymbolLoaderSettings settings = new SymbolLoaderSettings(SymbolsLoadMode.DynamicTree);
                IAdsSymbolLoader dynLoader = (IAdsSymbolLoader)SymbolLoaderFactory.Create(Client, settings);

                // Search for symbols with a specific attribute
                string desiredAttribute = "AddToConfig";  
                
                foreach (IAdsSymbol symbol in dynLoader.Symbols)
                {
                    if ( symbol.Attributes.Contains(desiredAttribute))
                    {
                        // Perform actions on the symbol that has the attribute
                        Console.WriteLine($"Symbol Name: {symbol.InstanceName}");
                        Console.WriteLine($"Symbol Path: {symbol.InstancePath}");
                        // ... Additional actions
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }

        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }

I get this error.

Error: Unable to cast object of type 'TwinCAT.TypeSystem.DynamicVirtualStructInstance' to type 'TwinCAT.Ads.TypeSystem.IAdsSymbol'.

Solution

  • The code you are trying to implement requires a little bit more of recursion to find nested variables inside global variable lists or also in a POUs (Program), i had a similar situation once and i developed the following solution:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using TwinCAT;
    using TwinCAT.Ads;
    using TwinCAT.Ads.TypeSystem;
    using TwinCAT.TypeSystem;
    
    namespace StackOverflow
    {
        internal class Program
        {
            static void Main()
            {
                try
                {
                    using (AdsClient Client = new AdsClient())
    
                    {
                        string ams = "172.18.233.27.1.1";
                        // Connect to the TwinCAT ADS router
                        Client.Connect(ams, 851);
                        //Creating a symbol loader
                        SymbolLoaderSettings settings = new SymbolLoaderSettings(SymbolsLoadMode.DynamicTree);
                        var symbolCollectionDict = (SymbolLoaderFactory.Create(Client, SymbolLoaderSettings.Default).Symbols as SymbolCollection).ToInstanceDictionary();
    
    
                        // Search for symbols with a specific attribute
                        string desiredAttribute = "AddToConfig";
    
                        foreach (var symbol in symbolCollectionDict)
                        {
                            var firstAttribute = symbol.Value.Attributes.FirstOrDefault(x => x.Name.Contains(desiredAttribute));
    
                            if (firstAttribute != null)
                            {
                                // Perform actions on the symbol that has the attribute
                                Console.WriteLine($"Symbol Name: {symbol.Key}");
                                Console.WriteLine($"Symbol Path: {symbol.Value.InstancePath}");
                                // ... Additional actions
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error: {ex.Message}");
                }
    
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }
    
    
    
    
    
        }
        // This static class will define extension methods that 
        // we are calling in our program
    
        public static class ExtMethods
        {
            public static Dictionary<string, Instance> ToInstanceDictionary(this ISymbolCollection symbolCollection)
            {
                if (symbolCollection == null)
                {
                    return new Dictionary<string, Instance>();
                }
    
                var dict = symbolCollection.ToDictionary(t => t.InstancePath, t => (Instance)t);
    
                foreach (var symbol in dict.Values.ToArray())
                {
                    dict.MergeDicts(GetMemeberList(symbol));
                }
    
                return dict;
            }
    
            private static Dictionary<string, Instance> GetMemeberList(Instance symbol)
            {
                var memberInstancesPropInfo = symbol.GetType().GetProperty("MemberInstances");
    
                if (memberInstancesPropInfo != null)
                {
                    var dict = ((ISymbolCollection)memberInstancesPropInfo.GetValue(symbol)).ToDictionary(t => t.InstancePath, t => (Instance)t);
    
                    foreach (var internalSymbol in dict.Values.ToArray())
                    {
                        dict.MergeDicts(GetMemeberList(internalSymbol));
                    }
    
                    if (dict.Count > 0)
                    {
                        return dict;
                    }
                }
    
                return new Dictionary<string, Instance>();
            }
    
            public static Dictionary<T1, T2> MergeDicts<T1, T2>(this Dictionary<T1, T2> masterDictionary, Dictionary<T1, T2> dictionaryToAppend)
            {
    
                foreach (KeyValuePair<T1, T2> keyValuePair in dictionaryToAppend)
                {
                    if (masterDictionary.ContainsKey(keyValuePair.Key) == false)
                    {
                        masterDictionary.Add(keyValuePair.Key, keyValuePair.Value);
                    }
                }
    
                return masterDictionary;
            }
        }
    
    }
    

    The extension methods handle the recursion and generate a dictionary where you can find the variable name and instance, after that you have to loop inside the attributes until you find the required variables, i tested with a small project in twincat 3. I got the following output in the console:

    Console output

    which is correct!

    Var declaration