问题
I have the following classes with an implicit cast operator defined:
class A
{
...
}
class B
{
private A m_a;
public B(A a)
{
this.m_a = a;
}
public static implicit operator B(A a)
{
return new B(a);
}
}
Now, I can implicitly cast A to B.
But why can't I implicitly cast A[] to B[] ?
static void Main(string[] args)
{
// compiles
A a = new A();
B b = a;
// doesn't compile
A[] arrA = new A[] {new A(), new A()};
B[] arrB = arrA;
}
Thanks, Malki.
回答1:
As Mehrdad Afshari mentioned, you're out of luck doing this implicitly. You'll have to get explicit, and it'll involve an array copy. Thankfully, you can probably do it with a one-liner:
arrB = arrA.Cast<B>().ToArray();
Although if you only want to iterate arrB
in a foreach
statement, you can avoid the copy by omitting ToArray()
回答2:
Array covariance only works for reference types and in the inheritance hierarchy (note that it's not a representation-changing conversion: just a set of pointers with identical size interpreted differently.) It will not work for value types and user defined conversions.
回答3:
ConvertAll
Just to be explicit, here is how you use ConvertAll.
In the case where class B
has a member of class A
called m_a
, do this:
B[] arrB;
A[] arrA = Array.ConvertAll(arrB, b => b.m_a);
.
If class B
has some member data that you need to manipulate before you can return an object of type A (such as turning a bunch of numerical values into a string description), do this:
class B
{
public static A makeAfromB(B b)
{
// Do something with B data...
A a = new A("data made from B data")
return a;
}
// rest of class B implementation ...
}
// somewhere else in your code...
A[] arrA = Array.ConvertAll(arrB, new Converter<B, A>(B.makeAfromB));
.
You can also use Lambda functions:
A[] arrA = Array.ConvertAll(arrB, new Converter<B, A>(
delegate(B b)
{
// Do something with B data, though object b is const
A a = new A("data made from B data")
return a;
}));
.
It would be nice if ConvertAll could use the implicit operator to do the conversion, but I haven't figured out how to do that.
.
Cast
@Randolpho @bottlenecked
For the cases where you simply want to iterate and would prefer not to make a copy, using cast makes sense. However I have been unable to make it work.
I have an InkPoint
class which has a Point
object and some other members. I want to call the DrawLines(Pen, Point[])
function. However, I have an array of InkPoint[]
.
Here is my class and the code I currently have to use, which makes a copy:
public class InkPoint
{
public InkPoint(int x, int y)
{
point = new Point(x, y);
}
public Point point { get; set; }
public static implicit operator Point(InkPoint p)
{
return p.point;
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
InkPoint[] inkPoints = { new InkPoint(1,2), new InkPoint(3,4) };
Point[] points = Array.ConvertAll(inkPoints, x => x.point);
Pen pen = new Pen(Color.Black, 1);
e.Graphics.DrawLines(pen, points);
}
.
I would rather call this, but it won't compile, citing invalid arguments:
e.Graphics.DrawLines(pen, inkPoints.Cast<Point>()); // Compile err: invalid args
.
I've also tried iterating over a cast, but it throws an exception, citing the cast is not valid
foreach (Point p in inkPoints.Cast<Point>()) { } // Exception: cast not valid
.
I don't understand why the specified cast is not valid
since I've defined an implicit operator. I'm able to do the following just fine:
InkPoint ip = new InkPoint(10, 20);
Point p1 = ip; // implicit conversion
Point p2 = (Point)ip; // cast
.
For me, the situation is actually slightly more complicated than that. I actually have a list of InkPoints, List<InkPoint>
, but the DrawLines
function accepts only arrays. So my code looks like this:
List<InkPoint> inkPoints = new List<InkPoint>();
inkPoints.Add(new InkPoint(5, 10));
inkPoints.Add(new InkPoint(10, 15));
Point[] points = inkPoints.ConvertAll<Point>(x => x.point).ToArray();
I can rearrange it slightly to this:
Point[] points = Array.ConvertAll(inkPoints.ToArray(), x => x.point);
.
So I think there's actually two copies happening here. This is annoying since all I want to do is draw the lines. It doesn't seem unreasonable that the DrawLines
function should be able to iterate over some array/list that contains references to objects that can be implicitly converted to Point
objects.
回答4:
Imagine for a moment if Arrays used the same syntax as other collections in .Net, and what you're trying to compare is an Array<A>
with an Array<B>
. You wouldn't compare a List<A>
to a List<B>
. Well, that's essentially what you're trying.
I'd recommend using a simple extension method to get the result you want, you'll need to change your syntax slightly to say 'B[] arrB = arrA.ToBArray();`
static class ArrayCast {
public static B[] ToBArray(this A[] source) {
var result = new B[source.Length];
for (int i = 0;i < source.Length;i++)
result[i] = source[i];
return result;
}
}
来源:https://stackoverflow.com/questions/3047727/implicit-array-casting-in-c-sharp