简体   繁体   English

泛型类型无效

[英]Invalid cast with generic type

I want to make a function that takes a Position object and returns the latitude and longitude of this Position as a formated string. 我想制作一个函数,该函数接受一个Position对象,并以格式化字符串的形式返回此Position的纬度和经度。

But the problem is that I have 2 Position objects : one from Xamarin Forms and another one from a geolocation nugget. 但是问题是我有2个Position对象:一个来自Xamarin Forms,另一个来自地理位置块。

Position from Xamarin forms: Xamarin表格中的位置:

public Position(double latitude, double longitude);
public double Latitude { get; }
public double Longitude { get; }
...

And Position from the geolocation nugget: 地理位置定位块中的位置:

public Position();
public Position(Position position);
public double Latitude { get; set; }
public double Longitude { get; set; }
...

In order to have the two types working as one I made an interface : 为了使这两种类型合而为一,我制作了一个接口:

interface IPosition
{
    double Latitude
    {
        get;
        set;
    }

    double Longitude
    {
        get;
        set;
    }
}

So my function should accept those two objects in parameter as follow : 所以我的函数应该接受参数中的这两个对象,如下所示:

public static string PositionToCoordonates<T>(T p)
    {
        return ((IPosition)p).Latitude.ToString().Replace(",", ".") + " ," + ((IPosition)p).Longitude.ToString().Replace(",", ".");
    }

Unfortunatly it throws the error " System.InvalidCastException: Specified cast is not valid. " at runtime. 不幸的是,它在运行时引发错误“ System.InvalidCastException:指定的转换无效。 ”。

What am I doing wrong ? 我究竟做错了什么 ? I guess that I need some kind of dynamic cast but I'm not sure. 我想我需要某种动态转换,但我不确定。

PositionToCoordonates shouldn't be generic. PositionToCoordonates不应是通用的。 Making it generic is a way of saying that the parameter can be of any type . 使它通用是一种说法,该参数可以是任何类型 Your parameter can't be of any type, it needs to be an IPosition . 您的参数不能为任何类型,必须为IPosition Make the parameter of type IPosition , so that callers aren't allowed to pass in objects of another type (as they won't work), and you'll be able to see, from any compiler errors, what callers are passing in an object of the wrong type. 设置IPosition类型的参数,以便不允许调用者传递其他类型的对象(因为它们将无法工作),并且您将能够从任何编译器错误中看到调用者在传递一个类型错误的对象。

Note that once you change the parameter there will no longer be a reason for the method to be generic, nor will you need to be casting the parameter in the method body. 请注意,一旦更改了参数,就不再需要方法通用,也不需要在方法主体中强制转换参数。

If both your Position classes implement IPosition , all you need is 如果您的两个Position类都实现了IPosition ,那么您所需IPosition就是

public static string PositionToCoordonates(IPosition position)

There is no need for generics. 不需要泛型。

On the other hand, if those classes do not implement that interface (and that would be the case if you created it), you will have a bit of code duplication. 另一方面,如果这些类未实现该接口(创建接口时就是这种情况),则将有一些代码重复。

public static string PositionToCoordonates(Geolocation.Position position)
{
    return PositionToCoordinates(position.Latitude, position.Longitude);
}

public static string PositionToCoordonates(Xamarin.Position position)
{
    return PositionToCoordinates(position.Latitude, position.Longitude);
}

private static string PositionToCoordonates(double latitude, double longitude)
{
    return string.Format(...);
}

As a clarification on the second part of my answer: In C#, classes have to declare they implement an interface, it is not enough to have the properties/methods defined on that interface. 作为我答案第二部分的澄清:在C#中,类必须声明它们实现了一个接口,仅在该接口上定义属性/方法是不够的。

So, in your example, position as IPosition will be null , and (IPosition) position will throw an exception. 因此,在您的示例中, position as IPosition将为null ,并且(IPosition) position将引发异常。

For the above casts to work, Position has to be declared as 为了使以上演员正常工作,必须将Position声明为

class Position : IPosition
{
    ...
}

Because both Positions are not implemented by you you can't just invent an interface to use it for casts imho. 因为这两个Positions都不由您实现,所以您不能仅仅发明一个接口以将其用于投射imho。 In this scenario I would probably handle this as follows: 在这种情况下,我可能会如下处理:

void Main()
{
    var position1 = new Position1() { Lat = 10, Lon = 5 };
    var position2 = new Position1() { Lat = 12, Lon = 3 };
    Console.WriteLine(GetLatLon(position1));
    Console.WriteLine(GetLatLon(position2));
}

static string GetLatLon<T>(T input) 
{
    var position1 = input as Position1;
    var position2 = input as Position2;
    if (position1 != null)
    {
        return $"{position1.Lat}-{position1.Lon}";
    }
    if (position2 != null)
    {
        return $"{position2.Lat}-{position2.Lon}";
    }
    throw new ArgumentException(nameof(input));
}

class Position1 
{
    public double Foo { get; set ;}
    public int Lat { get; set;}
    public int Lon { get; set;}
}

class Position2 
{
    public int Lat { get; set; }
    public int Lon { get; set; }
}

Dynamic seems to be too heavy for this scenario where only 2 possible types are involved. 对于这种只涉及2种可能类型的情况,动态似乎太重了。 I don't know if the generic parameter is needed exactly but I left it in the hope, that boxing/unboxing will be avoided one time. 我不知道是否确实需要泛型参数,但我希望它能避免一次装箱/拆箱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM