0

Edited

This my IAnimal Interface

interface IAnimal
{
    string getName();
    int getAge();
    bool getGender();
    void eat();
}

This is my IWalk Interface

interface IWalk
{
    void walk();
}

This is my IBird Interface

interface IBird : IAnimal, IWalk
{

}

This is my IFlightless_bird Intreface

interface IFlightless_bird : IBird
{

}

This is my Iswim Interface

interface ISwim
{
    void swim();
}

This is my King_penguin Class

public sealed class King_penguin : IFlightless_bird, ISwim 
{
    private string name;
    private int age;
    private bool gender;

    public King_penguin(string name, int age, bool gender)
    {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public string getName()
    {
        return this.name;
    }

    public int getAge()
    {
        return this.age;
    }

    public bool getGender()
    {
        return this.gender;
    }

    public void eat()
    {
        Debug.WriteLine("I ate!");
    }

    public void walk()
    {
        Debug.WriteLine("I walked!");
    }

    public void swim()
    {
        Debug.WriteLine("I swam!");

    }
}

I have a dropdown which is filled with strings which have exactly the same name as all my animal classes. 1

This is the Code of the StartForm Form

public partial class StartForm : Form
{
    public StartForm()
    {
        InitializeComponent();
    }

    private void btnCreateAnimal_Click(object sender, EventArgs e)
    {
        string selected = comboBoxAnimal.SelectedItem.ToString();
        Debug.WriteLine(selected);
        var createAnimal = new CreateAnimalForm(selected);
        createAnimal.Show(this);
    }
}

When I have selected the animal, I want to define the parameters that are required by the constructor. 2

This is the code of the CreateAnimalForm Form

public partial class CreateAnimalForm : Form
{
    string animal;
    public CreateAnimalForm(string animal)
    {
        this.animal = animal;
        InitializeComponent();
    }

    private void btnCreateAnimal_Click(object sender, EventArgs e)
    {
        bool gender;
        string name = textBoxName.ToString();
        int age = int.Parse(textBoxAge.Text);
        if (radioButtonMale.Checked)
        {
            gender = true;
        }
        else
        {
            gender = false;
        }
        
        IAnimal AnyAnimal = new this.animal(name, age, gender);

    }
}

When I have defined the parameters, I want to be able to press the button and create an object using the defined parameters and the selected animal

Alwin
  • 47
  • 1
  • 12
  • I want to know how I can use the value of the variable as a class from which I want to create an object – Alwin May 10 '21 at 12:01
  • 1
    So you really have distinct classes per species? This will then require use of Reflection: get the type from the type name e.g. by [Type.GetType](https://learn.microsoft.com/en-us/dotnet/api/system.type.gettype?view=net-5.0#System_Type_GetType_System_String_) and then create an instance using [Activator.CreateInstance](https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance?view=net-5.0#System_Activator_CreateInstance_System_Type_System_Object___System_Object___). – Klaus Gütter May 10 '21 at 12:04
  • Should I edit my question and add some pictures for example how the classes are structured and which classes inherit from which class or is it not clear what I have in mind? @TimSchmelter – Alwin May 10 '21 at 12:31
  • I have a dropdown list which has some animals to choose from, the selection is passed on to the next form and a corresponding object is then to be created based on the selection. unfortunately, the value in the variable is only a string and cannot simply be called at the desired position. – Alwin May 10 '21 at 12:34
  • @TimSchmelter I have edited my Question I hope you understand my Question now a little bit better – Alwin May 10 '21 at 13:05
  • The three duplicates I put there previously would have been useful for you to get you started. Alas they've been removed. – mjwills May 10 '21 at 13:08
  • @mjwills Have I removed them? – Alwin May 10 '21 at 13:27
  • You didn't, no. Short answer though - make a little function that takes a string and does a switch and returns the type you want. – mjwills May 10 '21 at 13:50
  • @TimSchmleter I think I have an Answer – Alwin May 17 '21 at 07:06

2 Answers2

1

The simple switch can handle it if you know all animals at compile time.

private IAnimal CreateAnimal(string name, int age, bool gender)
{
    return name switch { 
        nameof(King_penguin) => new King_penguin(name, age, gender),
        _ => throw new NotSupportedException($"Unknown animal '{name}'")
    };
}
  • Have I to create this method for every animal? – Alwin May 11 '21 at 06:48
  • I will try this out and Hope this will work – Alwin May 11 '21 at 06:58
  • I don't know but this code seems like I'm getting the animal name from the form where I can enter the name, but that's not the case. I get the name of the class from the dropdown list – Alwin May 11 '21 at 07:05
  • You can rename parameter to typeName :) And for every Animal you'll have to write only new row "nameof(XYAnimal) => new XYAnimal(... constructor arguments ...)," Didn't know whether you have always 3 constructor arguments or not. For example some animals can be genderless so you could omit that parameter in constructor. But your answer looks a lot better. – Ondřej Kubíček May 18 '21 at 05:51
1

I solved my Problem with an AnimalFactory

public class AnimalFactory
{
    List<Type> animals = new List<Type>();

    public AnimalFactory()
    {
        LoadAnimals();
    }

    public IAnimal CreateInstance(string animalType, string name, int age, bool gender)
    {
        #region Linq
        var animal = animals
            .FirstOrDefault(a => a.Name == animalType);
        return Activator.CreateInstance(animal, name, age , gender) as IAnimal;
        #endregion
    }

    private void LoadAnimals()
    {
        string @namespace = "Zoo.Animals";
        //Reflection
        animals = Assembly.GetExecutingAssembly().GetTypes()
            .Where(t => t.IsClass && t.Namespace == @namespace)
            .Where(t => t.IsClass && !t.IsInterface)
            .ToList();

    }
}

I load all of my Animals into a List and compare them with the Animal I got from the StartForm when I know which Animal I selected I create an Instance of this Class

I replaced this code:

private void btnCreateAnimal_Click(object sender, EventArgs e)
{
    bool gender;
    string name = textBoxName.ToString();
    int age = int.Parse(textBoxAge.Text);
    if (radioButtonMale.Checked)
    {
        gender = true;
    }
    else
    {
        gender = false;
    }
    
    IAnimal AnyAnimal = new this.animal(name, age, gender);

}

with:

    private void btnCreateAnimal_Click(object sender, EventArgs e)
    {
        bool gender;
        string name = textBoxName.ToString();
        int age = int.Parse(textBoxAge.Text);
        if (radioButtonMale.Checked)
        {
            gender = true;
        }
        else
        {
            gender = false;
        }
        IAnimal animal = new AnimalFactory().CreateInstance(this.animal, name, age, gender);
    } 
Alwin
  • 47
  • 1
  • 12
  • i don't know if this Asnwer is too specific – Alwin May 17 '21 at 07:05
  • But I hope it can help some one – Alwin May 17 '21 at 07:05
  • Nice solution. I'll only suggest a little edit to change "X as IAnimal" to cast "(IAnimal)X" so it will throw Exception if created animal would not implement IAnimal interface and that bug will be visible sooner than some weird NullreferenceException thrown later. – Ondřej Kubíček May 18 '21 at 05:55
  • @OndřejKubíček could you write an answer with the code how it should look like? – Alwin May 20 '21 at 08:44