使用泛型类型的无效演员表

时间:2018-01-15 14:54:02

标签: c# templates interface casting xamarin.forms

我想创建一个接受Position对象的函数,并将此Position的纬度和经度作为格式化字符串返回。

但问题是我有2个Position对象:一个来自Xamarin Forms,另一个来自地理定位金块。

Xamarin表格中的位置:

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

来自地理定位金块的位置:

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

为了使这两种类型合为一体,我创建了一个界面:

interface IPosition
{
    double Latitude
    {
        get;
        set;
    }

    double Longitude
    {
        get;
        set;
    }
}

所以我的函数应该接受参数中的这两个对象,如下所示:

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

不幸的是,它在运行时抛出错误“ System.InvalidCastException:指定的强制转换无效。”。

我做错了什么?我想我需要某种动态演员,但我不确定。

3 个答案:

答案 0 :(得分:3)

PositionToCoordonates不应该是通用的。使其通用是一种说法,参数可以是任何类型的 。您的参数可以是任何类型,它必须是IPosition。制作IPosition类型的参数,以便不允许来电者传入其他类型的对象(因为他们不会工作),并且您将能够从任何编译器错误,调用者传递的错误类型的对象。

请注意,一旦更改了参数,就不再有理由使该方法成为通用的,也不需要在方法体中强制转换参数。

答案 1 :(得分:2)

如果您的Position类同时实施IPosition,则只需

public static string PositionToCoordonates(IPosition position)

不需要泛型。

另一方面,如果这些类没有实现该接口(如果你创建了它就会出现这种情况),你将会有一些代码重复。

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(...);
}

作为对我答案第二部分的澄清:在C#中,类必须声明它们实现了一个接口,仅仅在该接口上定义了属性/方法是不够的。

因此,在您的示例中,position as IPosition将为null(IPosition) position将引发异常。

要使上述演员表工作,Position必须声明为

class Position : IPosition
{
    ...
}

答案 2 :(得分:1)

因为你没有实现Positions这两个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; } } ,所以你不能发明一个接口来使用它来进行强制转换。在这种情况下,我可能会按如下方式处理:

import random
input_list = [1, 3, "rand", 2]

def rand_replacer(my_list):
    output_list = []
    for item in my_list:
        if item == "rand":
            while True:
                new_variable = random.randint(0, 4)
                if new_variable not in my_list:
                    output_list.append(new_variable)
                    break
        else:
            output_list.append(item)
    return output_list

对于只涉及2种可能类型的情况,动态似乎过于沉重。我不知道是否确实需要通用参数,但我希望能避免一次装箱/拆箱。