Как автоматически привести объект к конкретному типу без точной проверки его типа в C#? - PullRequest
1 голос
/ 01 марта 2020

Вот простая форма того, что я использую сейчас.

public class Connectable {
    public List<A> connectedA;
    public List<B> connectedB;

    public void Connectable()
    {
        connectedA = new List<A>();
        connectedB = new List<B>();
    }

    public void AddConnection(Connectable otherConnectable)
    {
        if (otherConnectable is A) {
            A a = (A)otherConnectable;
            connectedA.Add(a);
        }
        else if (otherConnectable is B) {
            B b = (B)otherConnectable;
            connectedB.Add(b);
        }
    }
}

public class A : Connectable {
}

public class B : Connectable {
}

Есть ли способ улучшить функцию AddConnection путем ее автоматического трансляции или что-то еще?

Я ищу способ заменить его на:

public void AddConnection(A a){
    connectedA.Add(a);
}

public void AddConnection(B b){
    connectedB.Add(b);
}

и использовать его через ключевое слово autocast, если что-то подобное существует.

A a=new A();
B b=new B();
A.AddConnection(autocast B);
B.AddConnection(autocast A);

Пожалуйста, предоставьте любые другие советы по улучшению моего текущего кода, если он плохой.

Обновление: я должен упомянуть, что я хотел сохранить 2 отдельных Списка в каждом классе, т.е. класс A будет иметь список A и B, а класс B также будет иметь списки A и B. Учитывая, пары AA, AB, BA ИЛИ BB, они добавляются друг к другу в Список. Я использую их в игровом движке. Лог c - это А, реагирует с подключенными А и Б разными способами. То же самое касается B. Он также реагирует с подключенными A и B.

Кроме того, это имя класса было IConnectable, потому что я первоначально использовал интерфейс, а затем изменил его на class. Исправлено сейчас. Ничего, кроме опечатки.

Пока что использование OfType вместе с одним списком (ответ @ patrick-magee), кажется, лучше всего соответствует тому, что я ищу.

Ответы [ 3 ]

3 голосов
/ 01 марта 2020

Зависит от того, чего вы действительно пытаетесь достичь. Но у вас может быть 1 тип коллекции, а затем, чтобы получить дочерние типы, вы можете сделать что-то вроде этого:

void Main()
{
    var connectable = new Connectable();

    connectable.AddConnection(new ConnectableA());
    connectable.AddConnection(new ConnectableB());

    var connectableAs = connectable.GetConnected<ConnectableA>();
    var connectableBs = connectable.GetConnected<ConnectableB>();   
}

public class Connectable
{
    private List<Connectable> connected;

    public Connectable()
    {       
        connected = new List<Connectable>();
    }

    public void AddConnection(Connectable connectable)
    {
        this.connected.Add(connectable);
    }

    public IEnumerable<Connectable> GetConnected<T>() where T : Connectable
    {
        return this.connected.OfType<T>();
    }
}

public class ConnectableA : Connectable
{

}

public class ConnectableB : Connectable
{

}
1 голос
/ 01 марта 2020

Это будет хорошо работать:

public void AddConnection(A a){
    connectedA.Add(a);
}

public void AddConnection(B b){
    connectedB.Add(b);
}

// ...

A a=new A();
B b=new B();
a.AddConnection(b);
b.AddConnection(a);

Что вы, вероятно, имели в виду, это:

Connection c1 = GetConnection(/* some arguments */);
Connection c2 = GetConnection(/* some arguments */);
c1.AddConnection(c2); //error: no suitable overload (or something like that)

Вот где вам пригодится ваша "автоматическая трансляция", но AFAIK нет такая вещь. То, что вы можете сделать, это использовать трюк, который используется в двойной отправке, но вам нужна только одна часть отправки:

public abstract class Connectable {
    public List<A> connectedA;
    public List<B> connectedB;

    public void Connectable()
    {
        connectedA = new List<A>();
        connectedB = new List<B>();
    }

    public void AddConnection(Connectable otherConnectable)
    {
        otherConnectable.AddTo(this);
    }

    public abstract void AddTo(Connectable otherConnectable);
}

public class A: Connectable {
    public override void AddTo(Connectable otherConnectable)
    {
        otherConnectable.connectedA.add(this);
    }
}

public class B: Connectable {
    public override void AddTo(Connectable otherConnectable)
    {
        otherConnectable.connectedB.add(this);
    }
}
0 голосов
/ 01 марта 2020

Ваш код требует много улучшений и исправлений, в дизайне и реализации. Но давайте проигнорируем это ради объяснения. Поскольку вы наследуете от Connectable (изменено IConnectable на Connectable - I - имя некоторого класса ... это соглашение для интерфейса, а это класс - не используйте I , если это не интерфейс).

Все производные классы (A и B) также Connectable, потому что это их базовый класс, поэтому вы можете использовать виртуальные методы и полиморфизм , пожалуйста, прочитайте комментарии в этом примере:

class Program
{
    static void Main(string[] args)
    {
        Connectable obj = new Connectable();
        A a = new A();
        B b = new B();

        obj.AddConnection(a);
        obj.AddConnection(b);

        // show to console
        obj.ShowObjects();
        Console.ReadKey();

    }
}

// change IConnectable to Connectable - I is a convention for Interface and it is a class
public class Connectable
{
    // the list will be the base class (Connectable), all derived clasess (A,B) are also Connectable because they inherits Connectable
    public List<Connectable> connectedAANDB;

    public Connectable()
    {
        connectedAANDB = new List<Connectable>();
    }

    public void AddConnection(Connectable otherConnectable)
    {
        connectedAANDB.Add(otherConnectable);
    }

    // virtual method to override in each derived class in order to show the class name
    public virtual string WhoAmI()
    {
        return "I AM Connectable";
    }

    public void ShowObjects()
    {
        foreach (Connectable itm in connectedAANDB)
        {
            Console.WriteLine(itm.WhoAmI());
        } 
    }
}


public class A: Connectable
{
    public override string WhoAmI()
    {
        return "I AM A";
    }
}

public class B: Connectable
{
    public override string WhoAmI()
    {
        return "I AM B";
    }
}
...