代码之家  ›  专栏  ›  技术社区  ›  Jimmy Hoffa

从t到t的隐式或显式转换[]

  •  4
  • Jimmy Hoffa  · 技术社区  · 14 年前

    有没有一种方法可以实现一个通用的隐式或显式转换器,将任何内容转换为一个数组,比如:

    public static implicit operator T[](T objToConvert)
    {
        return new T[] { objToConvert };
    }
    
    6 回复  |  直到 14 年前
        1
  •  1
  •   Kirk Woll    14 年前

    运算符重载方法必须位于其重写运算符的类内(一侧或另一侧)。因为“T”没有定义,所以我不知道如何实现。

        2
  •  7
  •   driis    14 年前

    不,我能想到的最接近的方法是扩展方法:

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

    用作:

    var myArray = myInstnace.AsArray();
    
        3
  •  7
  •   Dan Bryant    14 年前

    注意,可以从数组构造函数中省略类型名,这意味着语法相当干净,即使类型名很长:

    ReallyLongAndAwkwardTypeName value;
    MethodThatTakesArray(new[] {value}); 
    
        4
  •  0
  •   Andrea Parodi    14 年前

    您可以使用普通方法:

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

    我认为您不能定义泛型运算符。注意,无论如何,编译器是足够的切割器来猜测泛型参数的类型,因此您可以使用:

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

    AstringArray被定义为字符串数组,即使不指定泛型参数。

        5
  •  0
  •   Dr. Wily's Apprentice    14 年前

    我试着考虑一些情况,在这些情况下,您可能真的使用隐式到数组的转换。我开始怀疑,在许多情况下,如果你想这样做,可以通过使用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!
        }
    

    当然,在需要将变量转换为单个项数组但不作为方法参数或方法作者未使用params关键字的情况下,这并不能真正帮助您。

    但是前者会是什么样的情况呢?为属性分配数组?PSH。这种情况多久发生一次?

    后者呢?如果作者在可能的时候没有使用params关键字,那么就给他们发一封抱怨的电子邮件。如果作者是你自己,请在电子邮件中多加挑衅。

    希望你能看出我在开玩笑。不过,说真的,还有没有其他常见的使用情况,您可以考虑在哪些情况下,params关键字将不适用?

    **免责声明:我不主张过度使用params关键字。如果你认为你应该使用它,但是不要把我的帖子理解为你应该随时使用params关键字。

        6
  •  0
  •   Dr. Wily's Apprentice    14 年前

    在过去,我使用了“导体”(我自己的名字)的概念,它只是一个类/结构,提供对底层值的访问。

    这个概念对于抽象从某个地方检索到的特定值的访问非常有用。例如,如果要抽象地访问字典中的特定值,可以创建一个包含对字典的引用的导体对象以及该值的相应键。您也可以使用这个概念来方便地实现可序列化类或值类型的回滚,尽管为此,您需要向导体类/结构添加回滚和提交方法。

    下面是一个示例,说明如何使用从t到conductor和从conductor到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;
        }
    }