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

时间:2010-08-20 15:25:33

标签: c# .net generics

有没有办法为任何事物的数组实现通用的隐式或显式转换器,如下所示:

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

6 个答案:

答案 0 :(得分:7)

没有。我能想到的最接近的是扩展方法:

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

用作:

var myArray = myInstnace.AsArray();

答案 1 :(得分:7)

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

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

答案 2 :(得分:1)

运算符重载方法必须存在于它们覆盖运算符(一侧或另一侧)的类中。由于“T”没有定义,我不知道如何实现。

答案 3 :(得分:0)

您可以使用常规方法执行此操作:

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

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

var aString="";
var aStringArray=ToArray(aString);
即使您没有指定泛型参数,

aStringArray也被定义为字符串数组。

答案 4 :(得分: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!
    }

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

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

后者?如果作者没有使用params关键字,那么就向他们发送一封抱怨它的电子邮件。如果作者是你自己,请随时在电子邮件中表现出更好的交战。

希望你能说出我是个滑稽的人。但是,严重的是,还有其他常见的使用情况,你可以想到params关键字不适用的地方吗?

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

答案 5 :(得分:0)

在过去,我使用了“指挥”(我自己的名字)的概念,它只是一个提供对基础价值的访问的类/结构。

该概念对于抽象对从某处检索的特定值的访问非常有用。例如,如果要抽象对字典中特定值的访问,可以创建一个Conductor对象,该对象包含对字典的引用以及该值的相应键。您还可以使用此概念轻松实现可序列化类或值类型的回滚,但为此您需要将Rollback和Commit方法添加到Conductor类/结构中。

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