Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping a Generic class inside a non Generic class C#

Tags:

c#

I'm working on a C# console application. My objective is to create an object called GroupEntity, preferably of non generic type.

Inside this GroupEntity object will be a List of 'AttributeFilter' object which contains object of Generic type which hold the attribute name on a user object in Active Directory and the possible values of those user objects. The reason I want the AttributeFilter object to take a generic type is because some attributes on user objects in AD are string, some are int32, some are int64 etc.

Here are my classes (I've cut out the contructorse etc to save space here)

    public class AttributeFilter<T> : IEqualityComparer<AttributeFilter<T>>
        {
            private string _attributeName;      
            private T _attributeValue;         
            private List<T> _attributeValues { get; set; }  

            public AttributeFilter(string attributeName)
            {
                AttributeName = attributeName;
                _attributeValues = new List<T>();
            }

            public void AddValues(T attributeValue)
            {
                AttributeValue = attributeValue;
                if (!_attributeValues.Contains(AttributeValue))
                {
                    _attributeValues.Add(AttributeValue);
                }
            }

// Ive cut out the getter setter etc that is not relevant
}

Here is the GroupEntity class. Notice I have a

List<AttributeFilter<T>>

field. Problem is I dont know what that T will be until I run program.cs

public class GroupEntity<T>
{
    private string _groupName;

    // because I want to a have a List<AttributeFilter<T>>, but I dont really want this here. because of program.cs when I initialise  a new GroupEntity<> I have to tell it what type. I wont know. The type could be int32, string, long or whatever.
    private List<AttributeFilter<T>> _filters;

    public void AddFilters(AttributeFilter<T> attributeFilter)
    {
        if (!_filters.Contains(attributeFilter, attributeFilter))
        {
            _filters.Add(attributeFilter);
        }
    }

    public GroupEntity()
    {
        _filters = new List<AttributeFilter<T>>();
    }

    public GroupEntity(string groupName) : this()
    {
        _groupName = groupName;
    }

}

Now I use program.cs to initialise and test...

    class Program
    {
        static void Main(string[] args)
        {

            // Create AttributeFilter object for user attribute: EYAccountType
            var at1 = new AttributeFilter<string>("EYAccountType");
            at1.AddValues("02");            
            at1.AddValues("03");
            at1.AddValues("04");
            at1.AddValues("05");


            // try adding anothr AtributeFilter with same name. 
            var at3 = new AttributeFilter<string>("EYAccountType1");
            at3.AddValues("06");
            at3.AddValues("07");



            // Create AttributeFilter object for user attribute: userAccountControl
            var at2 = new AttributeFilter<int>("userAccountControl");
            at2.AddValues(512);
            at2.AddValues(544);
            at2.AddValues(546);
            at2.AddValues(4096);


            // Now create a GroupEntity object 
            var group1 = new GroupEntity<string>("My_First_AD_Group_Name");


            // Try adding the above two AttributeFilter objects we created to the GroupEntity object.
            group1.AddFilters(at1);
            group1.AddFilters(at3);

            // This is the problem. I know why this is happening. because I initialised the var group1 = new GroupEntity<string>. So it wont accept at2 because at2 is taking in int. 
            //group1.AddFilters(at2);

}

So how can I write my GroupEntity class without a generic parameter so I can hold various types of AttributeFilter<T> inside it. So for example, I can hold AttributeFilter<int> and AttributeFilter<string> and AttributeFilter<long>

I can't seem to figure out this problem.

like image 710
user5078178 Avatar asked Oct 30 '22 09:10

user5078178


1 Answers

More or less you can't.

Generic types instantiated with different types has no relationship to each other (i.e. AttributeFilter<long> and AttributeFilter<int> don't get any common base class - they are as differnet as Exception and HttpClient). So there is no way to put instances of such types into single collection with strong typing.

Standard solution - use non-generic base class or interface for your AttributeFilter<T> type. Alternatively - store them as collection of object and lose all type safety, or maybe collection dynamic which at least give you chance to call methods (at cost of reflection).

like image 197
Alexei Levenkov Avatar answered Nov 15 '22 06:11

Alexei Levenkov