Как подойти к рефакторингу этого кода (C#, Типы)

Прежде всего, мои извинения за название вопроса. Я не совсем уверен, как это называется, что я пытаюсь достичь, поэтому я просто пойду прямо к этому.

В настоящее время я разрабатываю игровой движок на C# с использованием GDI+ и реализовал класс компонентов. Идея состоит в том, что к любому игровому объекту может быть присоединено несколько компонентов (во многом как в Unity3D), и я хочу иметь возможность находить любой компонент любого типа, ища, какой это класс.

На этой ноте я хотел бы изменить этот кусок кода:

Rigidbody r = obj.GetComponentOfType(typeof(Rigidbody)) as Rigidbody;

Чтобы выглядеть так вместо этого:

Rigidbody r = obj.GetComponentOfType<Rigidbody>();

Как мне это сделать?

Извините, если мой вопрос кажется расплывчатым, любой свет на эту тему будет замечателен!

8 ответов

Это называется универсальным методом. Вы можете создать перегрузку, которая вызывает вашу существующую реализацию на основе типов следующим образом:

public T GetComponentOfType<T>()
{
    return (T) GetComponentOfType(typeof(T));
}

Если у вас есть List<Component> поле в типе вашего объекта. Ты можешь использовать Linq:

// assuming
public class GameObject
{
    List<Component> m_Components; // all components attached to this GameObject
    public TComponent GetComponentOfType<TComponent>()
        where TComponent : Component
    {
        // Select only the ones of type TComponent and return first one
        return m_Components.OfType<TComponent>().FirstOrDefault();
    }
}

Чтобы использовать это: obj.GetComponentOfType<Rigidbody>();

Я думаю, что вы хотите реализовать универсальный метод, как показано ниже:

using System.Linq;
using System.Collections.Generic;

/// <summary>
/// Base-Class
/// </summary>
public abstract class Thing
{
    private ICollection<Thing> _things;

    public Thing()
    {
        _things = new List<Thing>();
    }

    public void AddSomething(Thing toAdd)
    {
        _things.Add(toAdd);
    }

    /// <summary>
    /// Assuming that every type can only appear once
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public T GetComonentOfType<T>() where T : Thing
    {
        return this.GetComonentOfType(typeof(T)) as T;
    }

    public Thing GetComonentOfType(Type t)
    {
        return _things.Where(x => x.GetType() == t).Single();
    }

}

/// <summary>
/// One possible implementation
/// </summary>
public class SpecialThing : Thing
{

}

Если вы не можете изменить класс, вы можете использовать метод расширения:

public static T GetComponentOfType<T>(this [objType] obj)
where T : class
{
    return obj.GetComponentOfType(typeof(T)) as T;
}

Это делается с помощью дженериков. Тело метода GetComponentofType будет практически идентичным, единственное отличие состоит в том, что вы задаете нужный тип через универсальный, а не передаете его в качестве параметра.

Метод может выглядеть так:

 public T GetComponentOfType<T>(){

      //code goes here to locate the object.
      you can get the type via typeof(T) 

      return theObject;
 }

Предполагая, что все классы компонентов наследуют этот класс (или похожий):

public abstract class IComponent
{
    protected IList<object> objComponents;

    public object GetComponentOfType(Type type)
    {
        if (objComponents == null)
            return null;

        return objComponents.Where(obj => obj.GetType() == type).FirstOrDefault();
    }
}

Вы можете просто создать другой основной материнский класс для наследования от:

public abstract class BaseComponent : IComponent
{
    public object GetComponentOfType<T>()
    {
        return GetComponentOfType(typeof(T));
    }
}

Или, если у вас есть доступ к первому классу, просто добавьте к нему предыдущую функцию.

Добавьте метод расширения к методу GetComponentOfType, который выполняет всю грязную работу за вас (первая строка кода, которую вы разместили), и пусть он принимает универсальный тип. Затем вы можете передать тип Rigidbody в теги <>.

Для получения дополнительной информации о методах расширения перейдите сюда.

Изменить: убедитесь, что ваш метод расширения является статическим.

Надеюсь, поможет.

   public class Rigidbody{
        public int Size{ get; set; }
        public string fourgroundColor{ get; set; }
        public string backgroundColor{ get; set; }
        public int fingerammount{ get; set; }
        public int arms{ get; set; }
    }

создать класс с именем Rigidbody. Установите все компоненты класса, чем вы могли бы его использовать. Олсо сделайте это публичным, иначе вы не сможете использовать его как ваш пример.

когда у вас есть класс, вы можете сказать: var r = obj.GetComponentOfType(); Также используйте var вместо типа данных. var лучше тип данных oldscool (больше похожий на C#1 или C2.0) я каждый раз совершал одну и ту же ошибку. но когда я начал работать разработчиком программного обеспечения, мне сказали, что я должен использовать var (я все еще младший, самый старый посредник)

Другие вопросы по тегам