简体   繁体   English

在运行时确定是否允许强制转换(C#)

[英]Determine at runtime if a cast is allowed (C#)

I have a C# wraper class with a series of methods accepting various data types: 我有一个带有一系列接受各种数据类型的方法的C#包装器类:

public class MyClass
{
    public void ProcessString(string Value) { // implementation }
    public void ProcessInt(int? Value) { // implementation }\
    public void ProcessOther(MyClass Value) { // implementation }
}

I now want to add a generic ProcessObject() method to avoid the need to explicitly cast an object before calling a relevant process method: 我现在想添加一个通用的ProcessObject()方法,以避免在调用相关的处理方法之前显式转换对象的需要:

public void ProcessObject(object Value)
{
    if (CanCastToString(Value)
    {
        ProcessString((string)Value);
    }
    else if (CanCastToInt(Value))
    {
        ProcessInt((int?)Value);
    }
    // etc...
}

The trouble is that I don't know what my CanCastToInt methods should be - I need these methods to be able to be robust and deal with things like nullable types and other user defined casts. 问题是我不知道我的CanCastToInt方法应该是什么-我需要这些方法能够变得健壮并能够处理可空类型和其他用户定义的类型转换。

How can I do this? 我怎样才能做到这一点? All I want to know is if a given object can be cast to a given type, ie whether or not: 我只想知道是否可以将给定的对象强制转换为给定的类型,即是否:

(SomeType)Value

Will work. 将工作。

There are two main ways this is usually done: 通常有两种主要方法:

if (Value is SomeType)
{
    // Do something with a cast
}

or 要么

var v = Value as SomeType;
if (v != null)
{
    // Value was successfully cast as SomeType
}

When working with structs or intrinsic types, make them nullable: 使用结构或内部类型时,使它们可为空:

var v = Value as int?;
if (v != null)
{
    ProcessInt(v.Value);
}

you need is operator. 您需要的is操作员。 CanCastToString(x) -> x is string . CanCastToString(x) -> x is string

Why not expose your processing API directly, with overloads for various parameters? 为什么不直接使用各种参数的重载直接公开您的处理API?

public class MyClass
{
    public void Process(string Value) { // implementation }
    public void Process(int Value) { // implementation }\
    public void Process(MyClass Value) { // implementation }
    public void Process(object Value) { // catch all method. Handle unknown entities, e.g. call ToString() }
}

EDIT With some generics magic you can have a single interface method, a bunch of helper methods that do the work and one catch-all method where you handle corner cases. 编辑使用一些泛型魔术,您可以拥有一个单一的接口方法,一堆可以完成工作的助手方法以及一个处理极端情况的万能方法。

public class MyClass
{
    void DoProcess(string Value) { // implementation }
    void DoProcess(int Value) { // implementation }\
    void DoProcess(MyClass Value) { // implementation }
    void DoProcess(object Value) { 
        // catch all method. Handle unknown entities, e.g. call ToString()
    }
    public void Process<T>(T value) {
       //this method will call the right overload of DoProcess depending on the compile time type of value. If there isn't a match, it goes to DoProcess(object)
       DoProcess(value);
    }
}

This way you avoid boxing for fundamental types and have slightly better type safety. 这样,您可以避免对基本类型进行装箱,并且具有更好的类型安全性。

For your catch-all method you can try using Type.IsAssignableFrom method. 对于所有方法,您可以尝试使用Type.IsAssignableFrom方法。 For example: 例如:

if (typeof(short).IsAssignableFrom(Value)
    DoProcess((short)Value);
if (typeof(byte).IsAssignableFrom(Value)
    DoProcess((byte)Value);

I do recommend that you read Eric Lippert's essay about representation casts. 我建议您阅读埃里克·利珀特(Eric Lippert)关于代表性演员的文章。 Hopefully, after doing that, you will come to realisation that it might just be easier to have an overload for each supported type. 希望这样做之后,您将认识到,每种受支持的类型都有一个重载可能会更容易。 Also, you might realise that dealing with unboxing value types could be a road to hell. 另外,您可能会意识到处理拆箱值类型可能是通往地狱的道路。

If (unlike OP?) you don't know the type involved until runtime you may try to employ some variation of this: 如果(与OP不同?)直到运行时您都不知道所涉及的类型,则可以尝试采用以下形式:

http://codegoeshere.blogspot.com/2007/05/dynamic-cast-in-c.html http://codegoeshere.blogspot.com/2007/05/dynamic-cast-in-c.html

    public void QuickTest()
    {
        object stringObj = "string";
        object nullableInt1 = (int?)null;
        object nullableInt2 = (int?)1;
        object decimalObj = 1.5m;

        ProcessObject(stringObj);
        ProcessObject(nullableInt1);
        ProcessObject(nullableInt2);
        ProcessObject(decimalObj);
    }

    public void ProcessObject(object value)
    {
        if (value == null)
        {
            Debug.WriteLine("null");
            return;
        }


        if (value is string)
        {
            Debug.WriteLine((string)value);
            return;
        }

        string stringValue = value.ToString();

        int intTemp;
        if (int.TryParse(stringValue, out intTemp))
        {
            Debug.WriteLine(intTemp);
            return;
        }

        decimal decimalTemp;
        if (decimal.TryParse(stringValue, out decimalTemp))
        {
            Debug.WriteLine(decimalTemp);
            return;
        }
        // etc...
    }

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

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