Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
185 views
in Technique[技术] by (71.8m points)

c# - Instantiating a class given a generic abstract type

Using this model:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    #region Abstracts definitions
    abstract class AnAbstract
    {
        public string Name { get { return this.GetType().Name; } }
        public bool IsNumeric { get { return this is ANumericAbstract; } }
        public /*abstract*/ string Description = default(string);
    }
    abstract class ANumericAbstract : AnAbstract
    {
        public /*abstract*/ double Min = double.MinValue;
        public /*abstract*/ double Max = double.MaxValue;
    }
    abstract class ANonNumericAbstract : AnAbstract
    {
        public List<Object> objects = new List<Object>();
    }
    #endregion Abstracts definitions
    #region Concrete definitions
    class NumericImpl : ANumericAbstract
    {
        new public const string Description = "A numeric implementation";
        new public const double Min = 0;
        new public const double Max = 1000;
        public NumericImpl()
        {
        }
    }
    abstract class AnotherImpl : ANonNumericAbstract
    {
        public AnotherImpl()
        {
            objects.Add("one");
            objects.Add("two");
            objects.Add("three");
        }
    }
    class SideA : AnotherImpl
    {
        new public const string Description = "Disc side A";
    }
    class SideB : AnotherImpl
    {
        new public const string Description = "Disc side B";
    }
    #endregion Concrete definitions
    partial class Parameter
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public bool IsNumeric { get; private set; }
        public double Min { get; private set; }
        public double Max { get; private set; }
        public List<Object> Values { get; private set; }
        private Parameter()
        {
            Values = new List<Object>();
        }
    }
}

With this, I pretend to define a hierarchy of classes for which I can have some abstract properties (Name,Description,IsNumeric) and at the end of the hierarchy there should be some classes which mandatorily define those properties; in the case of ANumericAbstract they should have additional specific properties, e.g. Min and Max.

Now here's the problem.

I'm attemtping to be able to create instances of Parameter which take a generic AnAbstract and read from it some values to fill in the Parameter properties, à la

Parameter<ANumericAbstract> ParamNum = new Parameter<NumericImpl>();

where a Parameter constructor would take in the passed type and "fill in the blanks". In other words, I'm trying something like:

using System;
namespace ConsoleApplication1 {
    partial class Parameter 
    {
        public static Parameter NewParameter<T>() where T : AnAbstract
        {
            Parameter Parameter = new Parameter();

            // THESE DON'T WORK:
            this.Name = T.Name;
            this.Description = T.Description;
            this.IsNumeric = T.IsNumeric;
            if (this.IsNumeric) 
            {
               this.Min = (T as ANumericAbstract).Min;
               this.Max = (T as ANumericAbstract).Max; 
            }
            else 
            {
              foreach(Object val in (T as ANonNumericAbstract).Values)
              {
                this.Values.Add(val);
              }
            }

            return Parameter;
        }
    }

    class Program
    {
        private AnAbstract Number = new NumericImpl();
        static void Main(string[] args)
        {
        }

        // THESE DON'T WORK:
        private static Parameter<ANumericAbstract> ParameterNum = 
                       Parameter.NewParameter<NumericImpl>();
        private static Parameter<ANonNumericAbstract> ParameterA = 
                       Parameter.NewParameter<SideA>();
        private static Parameter<ANonNumericAbstract> ParameterB = 
                       Parameter.NewParameter<SideB>();
    }
}

Obviously the syntax is invalid, but I'm not sure if I'm going in the right direction. Is there some Generics syntax that I'm not using properly? Should I just be done with it and use Getters and Setters à la Java? :-) At this point, just doing the

Parameter par = new Parameter { Name = NumericImpl.Name, /* ... */ };

might seem more sensible...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Firstly you should not use New keyword on your properties. Consider virtual keyword:

abstract class AnAbstract
{
    public virtual string Name { get { return this.GetType().Name; } }
    public virtual string Description { get { return String.Empty; } }
}
abstract class ANumericAbstract : AnAbstract
{
    public virtual double Min = double.MinValue;
}

class NumericImpl : ANumericAbstract
{
    public override string Description { get { return "A numeric implementation"; } } 
    public override double Min { get { return 0; } }
}

1) You can place an instance of you type in Parameter constructor and have Parameter instance.

partial class Parameter 
{ 
    public Parameter(AnAbstract inputObject) 
    { 
        this.Name = inputObject.Name; 
        // etc
    } 
}

private static Parameter ParameterNum = new Parameter(new NumericImpl());

2) The second way is to use reflection to create an instance of object with initial parameters.

    partial class Parameter<T> where T : AnAbstract
    {
        public static Parameter<T> NewParameter<T>() where T : AnAbstract
        {
            Parameter<T> parameter = new Parameter<T>();
            AnAbstract instance = (AnAbstract)Activator.CreateInstance(typeof(T));

            parameter.Name = instance.Name;
            // etc
            return parameter;
        }
    }

    private static Parameter<NumericImpl> ParameterNum = 
        Parameter<NumericImpl>.NewParameter();

3) Make Parameter class static and create in via static constructor.

static partial  class Parameter<T> where T : AnAbstract
{
    public static string Name { get; set; }
    //etc
}

static partial class Parameter<T> where T : AnAbstract
{ 
    static Parameter ()
    {
        AnAbstract instance = (AnAbstract)Activator.CreateInstance(typeof(T));
        Parameter<T>.Name = instance.Name;
        //etc
    }
}

In the last example you can use this class like this:

String someName = Parameter<NumericImpl>.Name;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...