Как работают методы расширения?

Я хочу сделать метод расширения в Unity3d для класса Vector3. Но я, кажется, не совсем понимаю. Вот что у меня есть:

public static class ExtensionMethods{

    public static Vector3 MaxValue(this Vector3 _vec3)
    {
        return new Vector3(float.MaxValue,float.MaxValue,float.MaxValue);
    }
}

Теперь я хочу сделать Vector3.MaxValue как float.MaxValue с этой строкой кода:

Vector3 closestPoint = Vector3.MaxValue;

Но тогда я получаю эту ошибку:

error CS0117: `UnityEngine.Vector3' does not contain a definition for `MaxValue'

Я знаю, что это будет работать:

Vector3 closestPoint = new Vector3().MaxValue();

Но потом я создаю 2 новых Vector3 экземпляров. Один в MaxValue позвони и один снаружи. Разве нельзя просто сделать один и сделать это с таким кодом:

Vector3 closestPoint = Vector3.MaxValue;

2 ответа

Решение

Во-первых, вот очень краткое руководство по расширениям для тех, кто изучает C#/Unity для тех, кто ищет в Google:

Создать новый текстовый файл HandyExtensions.cs как это... (обратите внимание, что несколько запутанно, вы можете использовать любое имя вообще для класса, который "содержит" ваши расширения - фактическое имя класса никогда не используется вообще, и не имеет значения)...

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;

 public static class HandyExtensions
     {
     public static float Jiggled(this float ff)
         {
         return ff * Random.Range(0.9f,1.1f);
         }
     }

Вы сейчас сделали новую "команду" Jiggle(), Вы можете использовать Jiggle на любом float, Посмотрите, где написано "этот поплавок ". Поскольку там написано "float", это расширение работает на float.

Как видите, Jiggled() Расширение возьмет поплавок и слегка его изменит. Попробуйте это так

 float x = 3.5f;
 Debug.Log("x is " + x);
 Debug.Log("x is " + x.Jiggled() );
 Debug.Log("x is " + x.Jiggled() );
 Debug.Log("x is " + x.Jiggled() );
 Debug.Log("x is " + x.Jiggled() );
 Debug.Log("x is " + x.Jiggled() );

Выполняйте подобные тесты, пока не разберетесь в расширениях. Узнайте как можно больше о расширениях! Вот еще один урок.

А теперь вопрос на этой странице!...


Как объясняет Микаэль, то, что вы ищете, на самом деле не является расширением. (Также обратите внимание, что если вы пытаетесь добавить поле в Vector3, вы не можете сделать это в C#.)

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

неправильно...

public static Vector3 MaxValue(this Vector3 _vec3)
{
    return new Vector3(float.MaxValue,float.MaxValue,float.MaxValue);
}

правильный...

public static Vector3 MaxValue()
{
    return new Vector3(float.MaxValue,float.MaxValue,float.MaxValue);
}

Вы можете сделать это...

Debug.Log(   ExtensionMethods.MaxValue()  );

Я думаю, что это может быть то, что вы ищете там.

Ты бы обычно звонил ExtensionMethods что-то короткое, как Handy так что вы можете написать

 Handy.MaxValue();

действительно, поскольку вы не можете поставить "Vector3 на передний план", что-то вроде этого будет более понятным:

  Handy.MaxVector3();

имеет смысл?

Если вы пытаетесь написать что-то вроде этого: Vector3.MaxValue() Вы не можете сделать это... потому что часть "Vector3" является классом (или структурой), а не переменной. Например, это расширение на целое число:

 375.Jiggle();

и это расширение на целое число:

 int x;
 x.Jiggle();

но это бессмысленно

 int.Jiggle();  // meaningless

Чтобы повторить для ясности, обратите внимание, что вы спросили:

Я хочу сделать метод расширения в Unity3d для класса Vector3 [на самом деле структура]

расширения могут быть вызваны только для реальных переменных, а не для "класса или структуры".

   Vector3 hero;
   Vector3 enemy;
   hero.Jiggle();  // works great
   enemy.Jiggle();  // works great

   Vector3.Jiggle();  // syntax error - meaningless

Заметьте также, что, как на самом деле упоминает Микаэль в своем ответе, вы на самом деле можете сделать это:

  (new Vector3()).Jiggle();

Если подумать, это тоже имеет смысл. Одна из моих любимых вещей в C# заключается в том, что вы можете использовать расширения для простых старых констант:

 14.Jiggle();
 7.5f.Radians();

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

public static Color Colored( this float alpha, int r, int g, int b )
    {
    return new Color(
        (float)r / 255f,
        (float)g / 255f,
        (float)b / 255f,
        alpha );
    }

Затем вы можете написать.. Color c = .5f.Colored(.2f,.4f,.2f); и это буйный цвет с альфой.5f.

Я всегда думал, что было бы замечательно, если бы синтаксис, о котором вы спрашиваете, был доступен, если бы вы могли иметь "тип" или "класс" как-то как "вещь", на которую вы расширяете, - но это не так. Для того, что вы пытаетесь сделать, вы просто должны использовать удобное слово, например, Handy, и сделать это

Vector3 big = Handy.MaxVec3();

Я надеюсь, что это объясняет ситуацию!


Опять же для тех, кому нужно общее введение в расширения, введение. Вот некоторые из моих любимых расширений.

Нечто подобное используется в каждом игровом проекте...

public static float Jiggle(this float ff)
    {
    return ff * UnityEngine.Random.Range(0.9f,1.1f);
    }

public static float PositiveOrNegative(this float ff)
    {
    int r = UnityEngine.Random.Range(0,2);
    if (r==0) return ff;
    return -ff;
    }

public static bool Sometimes(this int n)
    {
    if (n<=1) return true;
    int r = UnityEngine.Random.Range(0,n);
    return (r==0);
    }

Пример использования..

 if ( 10.Sometimes() )
   {
   explode spaceship
   }

это происходит только один раз из десяти.

 if ( 3.Sometimes() )
   {
   laser sparkle
   }

в этом примере он делает это только около трети времени.

(Обратите внимание, что, как правило, вы делаете расширения, где это возможно, с использованием обобщений. Не показано здесь для простоты.)

Вот удобный трюк с расширением. Вот действительно продвинутое расширение.

Расширения вездесущи в Unity engineering.

Если вы один из многих, кто учится программировать с использованием Unity... в первую очередь вам нужно освоить расширения. Попробуйте сделать почти все с расширением. Иногда при работе с Unity почти каждой строке кода требуется одно или несколько расширений. Наслаждайтесь!

Методы расширения - это способ сделать так, чтобы статические методы были частью класса или интерфейса. Метод расширения Foo() в Vector3 означает, что вы можете сделать новый Vector3().Foo(), как вы сказали.

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

Но действительно ли это необходимо? Вы можете просто определить свое постоянное свойство в новом типе. Давайте назовем это "KnownVectors" или что-то в этом роде:

Vector3 closestPoint = KnownVectors.MaxValue;

Конечно, может быть, было бы неплохо вставить это в существующий класс Vector3, но действительно ли это добавит что-то в ваш код?

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