简体   繁体   中英

How to create a collection of interfaces that have a generic type

I'm trying to make a framework that can be extended by the implementer. at a high level there will be a several different implementations of a base object, and all such instances of those different implementations will need to be processed together. the most versatile and elegant solution for the implementer would seem to be generic typing, but putting them together in a collection is tripping me up.

I've tried using a class or and interface that has a generic type, and then the implementation fixes it, but i cant build a list. for example

using System;
using System.Collections.Generic;

namespace GenericsMixingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new Container();
            container.Wrappers.Add(new IntWrapper { Value = 5 });
            container.Wrappers.Add(new IntWrapper { Value = 5 });
            container.Wrappers.Add(new StringWrapper { Value = "value" });
            container.Wrappers.ForEach((e) => { Console.WriteLine(e.Value.ToString()); });
        }
    }

    interface ValueWrapper<T>
    {
        T Value { get; set; }
    }

    class IntWrapper : ValueWrapper<int>
    {
        public int Value { get; set; }
    }

    class StringWrapper : ValueWrapper<string>
    {
        public string Value { get; set; }
    }

    interface IContainer
    {
        List<ValueWrapper> Wrappers { get; set; }
    }

    class Container : IContainer
    {
        public List<ValueWrapper> Wrappers { get; set; }
        public Container()
        {
            Wrappers = new List<ValueWrapper>();
        }
    }
}

but that gives the error Using the generic type 'ValueWrapper<T>' requires 1 type arguments when i try to define the list

i thought maybe an abstract class that returns object and then overriding the type would work:

using System;
using System.Collections.Generic;

namespace objectBased
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new Container();
            container.Wrappers.Add(new IntWrapper { Value = 5 });
            container.Wrappers.Add(new IntWrapper { Value = 5 });
            container.Wrappers.Add(new StringWrapper { Value = "value" });
            container.Wrappers.ForEach((e) => { Console.WriteLine(e.Value.ToString()); });
        }
    }

    abstract class IValueWrapper
    {
        public virtual object Value { get; set; }
    }

    class IntWrapper : IValueWrapper
    {
        private int _value;
        public override object Value {
            get { return _value; }
            set { _value = Convert.ToInt32(value); }
        }
    }

    class StringWrapper : IValueWrapper
    {
        private string _value;
        public override object Value
        {
            get { return _value; }
            set { _value = (value as string); }
        }
    }

    interface IContainer
    {
        List<IValueWrapper> Wrappers { get; set; }
    }

    class Container : IContainer
    {
        public List<IValueWrapper> Wrappers { get; set; }
        public Container()
        {
            Wrappers = new List<IValueWrapper>();
        }
    }
}

but this falls apart when i try to add more complexity:

abstract class IValueWrapper
    {
        public virtual object Value { get; set; }
        public abstract void Randomize();
        public abstract object MixValues(object otherValue);
    }

    class IntWrapper : IValueWrapper
    {
        public static int MAX_RANDOM = 100;
        private int _value;
        public override object Value {
            get { return _value; }
            set { _value = Convert.ToInt32(value); }
        }
        public override void Randomize()
        {
            Random rng = new Random();
            Value = rng.Next(0, MAX_RANDOM);
        }
        public override int MixValues(int otherValue)
        {
            int smaller = Math.Min(otherValue, Value);
            int larger = Math.Min(otherValue, Value);
            return smaller - (larger - smaller) / 2;
        }
    }

In the above block MixValues cannot override the abstract because the return type is different, the input type is different, and Value isn't an int. The abstract class method looks like it requires tons of casting that I'm not overly interested in.

As a stretch goal I would like to be able to have methods like mix be static methods that return a new instance of the class

public static IntWrapper MixValues()
{
    return new IntWrapper() //...etc
}

but i can live without that if its necessarily difficult

so is there any way i can make that list of generically typed parent objects?

Depends on what you want to do with the processing, but perhaps you could do something like this?

using System;
using System.Collections.Generic;

namespace GenericsMixingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new Container();
            container.Wrappers.Add(new IntProcessor { Value = 5 });
            container.Wrappers.Add(new IntProcessor { Value = 5 });
            container.Wrappers.Add(new StringProcessor { Value = "value" });
            container.Wrappers.ForEach((e) => { e.Process(); });
        }
    }

    interface IProcessor
    {
        void Process();
    }

    class IntProcessor : IProcessor
    {
        public int Value { get; set; }

        public void Process()
        {
            Console.WriteLine("Processing: " + Value);
        }
    }

    class StringProcessor : IProcessor
    {
        public string Value { get; set; }

        public void Process()
        {
            Console.WriteLine("Processing: " + Value);
        }
    }

    interface IContainer
    {
        List<IProcessor> Wrappers
        {
            get;
            set;
        }
    }

    class Container : IContainer
    {
        public List<IProcessor> Wrappers
        {
            get;
            set;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM