Как подойти к рефакторингу этого кода (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 (я все еще младший, самый старый посредник)