2010-08-20 2 views
4

Есть ли способ реализации общего неявного или явного нейтрализатор для чего-либо на массив ничего, что-то вроде этого:неявное или явное преобразование из T в T []

public static implicit operator T[](T objToConvert) 
{ 
    return new T[] { objToConvert }; 
} 
+0

Нет, я бы хотел, чтобы вы сделали это! :( – mquander

+4

это незаконное конвертирование - плохой шаблон ИМО. Что бы вы хотели сделать? Может быть, есть и другой способ сделать это –

ответ

1

оператора перегрузки методы должны жить внутри класса они являются переопределяющими операторами для (одной или другой). Поскольку «T» не определено, я не вижу, как это можно сделать.

+0

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

+0

Ха-ха, хороший комментарий.;) –

7

No. Ближайший я могу думать метод расширения:

public static T[] AsArray<T>(this T instance) 
{ 
    return new T[]{instance}; 
} 

Использование в качестве:

var myArray = myInstnace.AsArray(); 
+3

Такая вещь - это обоюдоострый меч. С одной стороны, использование общего метода, который может это сделать, может быть полезным, особенно при использовании с такими библиотеками, как LINQ, где иногда вам нужно, чтобы отдельные элементы были легко обработаны как последовательности. С другой стороны, это может быть болью, потому что общий метод расширения, подобный этому, проявляется для каждого типа в Intellisense и может смущать других разработчиков. Это также подвержено злоупотреблениям. В целом, быть консервативным в создании глобальных применимых методов расширения - это хорошо. Что касается 'AsArray' - я нахожусь на заборе. – LBushkin

+0

@ Л.Бушкин, согласен. У меня нет метода AsArray в моем текущем проекте; вместо этого я использую синтаксис инициализации массива. В зависимости от ситуации и использования OP, однако, имеет смысл использовать его как метод расширения. – driis

+0

У меня на самом деле нет случая использования, мне просто интересно, есть ли способ сделать это. –

7

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

ReallyLongAndAwkwardTypeName value; 
MethodThatTakesArray(new[] {value}); 
+0

Не знал этого, отличный ярлык! –

+0

Я не знал этого ни до тех пор, пока Решарпер не указал это. :) –

0

Вы можете сделать это обычным способом:

public static T[] ToArray<T>(T objToConvert) { 
    return new T[] { objToConvert }; 
} 

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

var aString=""; 
var aStringArray=ToArray(aString); 

aStringArray определяются как массив строк, даже если вы не укажете общие параметры.

0

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

Основное положение, что я мог думать только о том, что у вас один пункт что-то и хотел, чтобы передать его в функцию, которая принимает массив в качестве параметра:

static void Main(string[] args) 
    { 
     string x = "I'm just a poor variable. Nobody loves me."; 

     Stickler.IOnlyTakeArrays_Rawr111(x); // won't go in! square peg, round hole, etc. 

     // *sigh* fine. 
     Stickler.IOnlyTakeArrays_Rawr111(new[] { x }); 
    } 

    class Stickler 
    { 
     public static void IOnlyTakeArrays_Rawr111(string[] yum) 
     { 
      // ... 
     } 
    } 

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

class DataConcierge 
    { 
     public static T Create<T>(int id) 
     { 
      // ... 
     } 

     public static void Save<T>(params T[] items) 
     { 
      // ... 
     } 
    } 

    static void Main(string[] args) 
    { 
     var customer = DataConcierge.Create<Customer>(123); 

     // ... 

     DataConcierge.Save(customer); // this works! 

     //---------------------------------------------------- 
     // or 
     //---------------------------------------------------- 

     var customers = new Customer[] 
     { 
      DataConcierge.Create<Customer>(123), 
      DataConcierge.Create<Customer>(234), 
      DataConcierge.Create<Customer>(345), 
     }; 

     // ... 

     DataConcierge.Save(customers); // this works too! 
    } 

конечно, это не очень поможет вам в ситуациях, когда вы нужно преобразовать переменную в один элемент arr ay, но не как параметр для метода или в ситуациях, когда автор метода не использовал ключевое слово params.

Но какова бы ситуация была первой? Назначение массива для свойства? Psh. Как часто это происходит?

И последнее? Если автор не использовал ключевое слово params, когда они могли это сделать, отправьте им письмо с жалобой на него. Если автор сам, не стесняйтесь быть дополнительным воюющим в письме.

Надеюсь, вы можете сказать, что я преуспеваю. Серьезно, однако, существуют ли какие-либо другие общие ситуации использования, которые вы можете придумать, где ключевое слово params не применимо?

** Отказ от ответственности: Я не сторонник чрезмерного использования ключевого слова params. Используйте его, если вы считаете, что хотите, но не принимайте мое сообщение, чтобы вы всегда использовали ключевое слово params, когда можете.

+0

Так что вы говорите, что все методы sigs должны быть просто параметрами SomeMethod (params object [])? Согласен! Что это значит? В нем есть слово «лицо», вы пытаетесь понять, что у меня есть уродливое лицо? –

0

В прошлом я использовал концепцию «Дирижер» (мое собственное имя для нее), которое является просто классом/структурой, обеспечивающим доступ к базовому значению.

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

Ниже приведен пример того, как вы можете использовать неявные преобразования из T в проводник и от проводника к T [], чтобы (вроде) достичь того, чего вы хотите.

static void Main(string[] args) 
    { 
     // implicit conversion here from Customer to Conductor<Customer> 
     Conductor<Customer> conductor = DataConcierge.Create<Customer>(123); 

     if (conductor.HasValue) 
     { 
      Console.WriteLine("I got a customer with Id {0}!", conductor.Value.Id); 

      // implicit conversion here from Conductor<Customer> to Customer[] 
      DataConcierge.Save<Customer>(conductor); 
     } 
    } 



public struct Conductor<T> : IConductor<T>, IEquatable<T>, IEquatable<Conductor<T>>, IEquatable<IConductor<T>> 
{ 
    private T _Value; 

    public Conductor(T value) 
    { 
     this._Value = value; 
    } 

    public T Value 
    { 
     get { return this._Value; } 
     set { this._Value = value; } 
    } 

    public bool HasValue 
    { 
     get { return this._Value != null; } 
    } 

    public T GetValueOrDefault() 
    { 
     if (this.HasValue) 
      return this.Value; 
     else 
      return default(T); 
    } 

    public T GetValueOrDefault(T @default) 
    { 
     if (this.HasValue) 
      return this.Value; 
     else 
      return @default; 
    } 

    public bool TryGetValue(out T value) 
    { 
     if (this.HasValue) 
     { 
      value = this.Value; 
      return true; 
     } 
     else 
     { 
      value = default(T); 
      return false; 
     } 
    } 

    public T[] AsArray() 
    { 
     return new T[] { this._Value }; 
    } 

    public static implicit operator Conductor<T>(T value) 
    { 
     return new Conductor<T>(value); 
    } 

    public static implicit operator T(Conductor<T> conductor) 
    { 
     return conductor.Value; 
    } 

    public static implicit operator T[](Conductor<T> conductor) 
    { 
     return conductor.AsArray(); 
    } 

    public bool Equals(T other) 
    { 
     var otherEquatable = other as IEquatable<T>; 
     if (otherEquatable != null) 
      return otherEquatable.Equals(this.Value); 
     else 
      return object.Equals(this.Value, other); 
    } 

    public bool Equals(Conductor<T> other) 
    { 
     if (other.HasValue) 
      return this.Equals(other.Value); 
     else 
      return !this.HasValue; 
    } 

    public bool Equals(IConductor<T> other) 
    { 
     if (other != null && other.HasValue) 
      return this.Equals(other.Value); 
     else 
      return !this.HasValue; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return !this.HasValue; 

     var conductor = obj as IConductor<T>; 
     if (conductor != null) 
     { 
      if (conductor.HasValue) 
       return this.Equals(conductor.Value); 
      else 
       return !this.HasValue; 
     } 

     return object.Equals(this.Value, obj); 
    } 

    public override int GetHashCode() 
    { 
     if (this.HasValue) 
      return this.Value.GetHashCode(); 
     else 
      return 0; 
    } 

    public override string ToString() 
    { 
     if (this.HasValue) 
      return this.Value.ToString(); 
     else 
      return null; 
    } 
} 
Смежные вопросы