Проверка типа: typeof, GetType или есть?

Я все еще работаю над этим, поэтому я не буду публиковать весь исходный код. Но я дам вам концептуальное решение.

В качестве входных данных (для обеих камер) вам понадобятся следующие данные:

  • положение камеры
  • камера (точка, в которой камера смотрит)
  • разрешение камеры (горизонтальное и вертикальное)
  • поле обзора углов обзора (горизонтальное и вертикальное)

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

Камеры не обязательно должны быть выровнены, вам нужно только увидеть свой объект в обеих камерах.

Теперь вычислите вектор от каждой камеры к вашему объекту. У вас есть (X, Y) пиксельные координаты объекта с каждой камеры, и вам нужно вычислить вектор (X, Y, Z). Обратите внимание, что в простом случае, когда объект отображается прямо посередине камеры, решение будет просто (camera.PointOfInterest - camera.Position).

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

Расстояние между двумя линиями

В этой ссылке: P0 - это ваша первая позиция кулачка, Q0 - это ваша вторая позиция кулачка, а u и v - векторы, начинающиеся с положения камеры и указывающие на вашу цель.

Вас не интересует фактическое расстояние, которое они хотят рассчитать. Вам нужен вектор Wc - мы можем предположить, что объект находится в середине Wc. После того, как у вас есть позиция вашего объекта в 3D-пространстве, вы также получите любое расстояние, которое вам нравится.

Я скоро опубликую весь исходный код.

1387
задан jasonh 11 June 2009 в 19:10
поделиться

8 ответов

Все разные.

  • typeof принимает имя типа (которое вы указываете во время компиляции) .
  • GetType получает тип среды выполнения экземпляра.
  • is возвращает истину, если экземпляр находится в дереве наследования.

Пример

class Animal { } 
class Dog : Animal { }

void PrintTypes(Animal a) { 
    Console.WriteLine(a.GetType() == typeof(Animal)); // false 
    Console.WriteLine(a is Animal);                   // true 
    Console.WriteLine(a.GetType() == typeof(Dog));    // true
    Console.WriteLine(a is Dog);                      // true 
}

Dog spot = new Dog(); 
PrintTypes(spot);

А как насчет typeof (T) ? Это также разрешено во время компиляции?

Да. T всегда соответствует типу выражения. Помните, что универсальный метод - это, по сути, целый набор методов соответствующего типа. Пример:

string Foo<T>(T parameter) { return typeof(T).Name; }

Animal probably_a_dog = new Dog();
Dog    definitely_a_dog = new Dog();

Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.

Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal". 
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
1758
ответ дан 22 November 2019 в 20:19
поделиться

Используйте typeof , если вы хотите получить тип во время компиляции . Используйте GetType , если вы хотите получить тип во время выполнения . is редко используются, поскольку он выполняет приведение, и в большинстве случаев вы все равно приводите переменную.

Есть четвертый вариант, который вы не рассматривали (особенно если вы также собираетесь привести объект к найденному вами типу); то есть использовать как .

Foo foo = obj as Foo;

if (foo != null)
    // your code here

Здесь используется только одно преобразование, тогда как этот подход:

if (obj is Foo)
    Foo foo = (Foo)obj;

требует двух .

182
ответ дан 22 November 2019 в 20:19
поделиться

Я предпочитаю is

Тем не менее, если вы используете is , вы, скорее всего, не правильно используете наследование.

Предположим, что это лицо: сущность, а животное: сущность. Feed - это виртуальный метод в Entity (чтобы сделать Нила счастливым)

class Person
{
  // A Person should be able to Feed
  // another Entity, but they way he feeds
  // each is different
  public override void Feed( Entity e )
  {
    if( e is Person )
    {
      // feed me
    }
    else if( e is Animal )
    {
      // ruff
    }
  }
}

Скорее

class Person
{
  public override void Feed( Person p )
  {
    // feed the person
  }
  public override void Feed( Animal a )
  {
    // feed the animal
  }
}
9
ответ дан 22 November 2019 в 20:19
поделиться

1.

Type t = typeof(obj1);
if (t == typeof(int))

Это незаконно, потому что typeof работает только с типы, а не переменные. Я предполагаю, что obj1 - это переменная. Таким образом, typeof статичен и выполняет свою работу во время компиляции, а не во время выполнения.

2.

if (obj1.GetType() == typeof(int))

Это верно, если obj1 имеет именно тип int. Если obj1 является производным от int, условие if будет ложным.

3.

if (obj1 is int)

Это верно, если obj1 является int, или если он является производным от класса с именем int, или если он реализует интерфейс с именем int.

69
ответ дан 22 November 2019 в 20:19
поделиться

Я считаю, что последний также учитывает наследование (например, Dog is Animal == true), что в большинстве случаев лучше.

5
ответ дан 22 November 2019 в 20:19
поделиться

Это зависит от того, что я делаю. Если мне нужно значение типа bool (скажем, чтобы определить, приведу ли я к int), я буду использовать is . Если мне действительно нужен тип по какой-то причине (например, для перехода к другому методу), я буду использовать GetType () .

2
ответ дан 22 November 2019 в 20:19
поделиться

Последний более понятен, более очевиден и также проверяет наличие подтипов. Остальные не проверяют полиморфизм.

0
ответ дан 22 November 2019 в 20:19
поделиться
Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

Это ошибка. Оператор typeof в C # может принимать только имена типов, но не объекты.

if (obj1.GetType() == typeof(int))
    // Some code here

Это будет работать, но, возможно, не так, как вы ожидали. Для типов значений, как вы показали здесь, это приемлемо, но для ссылочных типов оно вернет истину только в том случае, если тип точно такой же , а не что-то еще в иерархии наследования. Например:

class Animal{}
class Dog : Animal{}

static void Foo(){
    object o = new Dog();

    if(o.GetType() == typeof(Animal))
        Console.WriteLine("o is an animal");
    Console.WriteLine("o is something else");
}

Это напечатает «o - это что-то еще» , потому что тип o - Dog , а не Animal . Однако вы можете справиться с этой задачей, если используете метод IsAssignableFrom класса Type .

if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
    Console.WriteLine("o is an animal");

Однако этот метод все еще оставляет серьезную проблему. Если ваша переменная равна нулю, вызов GetType () вызовет исключение NullReferenceException. Итак, чтобы он работал правильно, вы должны сделать:

if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
    Console.WriteLine("o is an animal");

Таким образом, у вас есть эквивалентное поведение ключевого слова is . Следовательно, если это именно то поведение, которое вам нужно, вам следует использовать ключевое слово is , которое более читабельно и более эффективно.

if(o is Animal)
    Console.WriteLine("o is an animal");

Однако в большинстве случаев ключевое слово is по-прежнему это не то, что вам действительно нужно, потому что обычно недостаточно просто знать, что объект относится к определенному типу. Обычно вы хотите на самом деле использовать этот объект как экземпляр этого типа, что тоже требует его приведения. И поэтому вы можете написать такой код:

if(o is Animal)
    ((Animal)o).Speak();

Но это заставляет CLR проверять тип объекта до двух раз. Он проверит его один раз, чтобы удовлетворить оператору is , и если o действительно является Animal , мы снова проверяем приведение, чтобы подтвердить приведение.

Это более эффективно:

Animal a = o as Animal;
if(a != null)
    a.Speak();

Оператор as - это приведение, которое не генерирует исключение в случае сбоя, вместо этого возвращает ноль . Таким образом, CLR проверяет тип объекта только один раз, а после этого нам просто нужно выполнить нулевую проверку, что более эффективно.

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

(o as Animal).Speak();

В этом случае разработчик явно предполагает, что o всегда будет Animal , и пока их предположение верное, все работает нормально. Но если они ошибаются, то в итоге они получают NullReferenceException . При обычном приведении они получили бы вместо этого InvalidCastException , что позволило бы более правильно определить проблему.

Иногда эту ошибку бывает трудно найти:

class Foo{
    readonly Animal animal;

    public Foo(object o){
        animal = o as Animal;
    }

    public void Interact(){
        animal.Speak();
    }
}

Это еще один случай, когда ошибка разработчик явно ожидает, что o каждый раз будет Animal , но это не очевидно в конструкторе, где используется приведение as . Это не очевидно, пока вы не дойдете до метода Interact , где ожидается, что поле animal будет положительно присвоено. В этом случае вы не только получите вводящее в заблуждение исключение, но и не сгенерируете его до тех пор, пока возможно намного позже, чем когда произошла фактическая ошибка.

В итоге:

  • Если вам нужно только знать, относится ли объект к какому-либо типу, используйте равно .

  • Если вам нужно рассматривать объект как экземпляр определенного типа, но вы этого не делаете Чтобы точно знать, что объект будет этого типа, используйте как и проверьте null .

  • Если вам нужно рассматривать объект как экземпляр определенного типа, и объект должен быть этого типа, используйте обычное приведение.

48
ответ дан 22 November 2019 в 20:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: