.net 在C#中将泛型类型参数强制转换为特定类型

j9per5c4  于 2023-01-03  发布在  .NET
关注(0)|答案(9)|浏览(382)

如果需要将泛型类型参数强制转换为特定类型,我们可以将其强制转换为对象,并按如下所示执行强制转换:

void SomeMethod(T t)
{
    SomeClass obj2 = (SomeClass)(object)t;
}

是否有更好的方法来实现这一点,而不是将其强制转换为对象,然后再转换为特定类型?
问题:
我有一个泛型函数,它接受一个泛型类型参数,在函数内部,基于类型检查,我做了如下操作:

void SomeMethod(T t)
    {
        if (typeof(T).Equals(typeof(TypeA)))
        {
            TypeA = (TypeA)(object)t;
            //Do some operation
        }
        else if (typeof(T).Equals(typeof(TypeB)))
        {
            TypeB = (TypeB)(object)t;
            //Do some operation
        }
    }
qltillow

qltillow1#

您可以使用Convert.ChangeType

SomeClass obj2 = (SomeClass)Convert.ChangeType(t, typeof(SomeClass));

不过,请记住,如果强制转换无效,这将引发异常。

fzsnzjdm

fzsnzjdm2#

使用as

SomeClass obj2 = t as SomeClass;

这不会引发异常,并且如果转换失败,t将为null。
我真的不知道你想做什么,但我希望你没有错过泛型的重点。
如果要将方法限制为SomeClass及其后代类型:

void SomeMethod(T t)  where T : SomeClass
8fsztsew

8fsztsew3#

一个更好的设计是对它施加一个约束,该约束在类型T和您希望在方法中使用的类之间是通用的,在本例中是SomeClass

class SomeConsumer<T> where T : ISomeClass
{
    void SomeMethod(T t)
    {
        ISomeClass obj2 = (ISomeClass) t;
    }
}

interface ISomeClass{}

class SomeClass : ISomeClass {}

根据问题的编辑进行编辑

这是一个糟糕的设计。试着把那个“操作”移到类本身中,这样调用者就不必知道类型了。如果这不可能共享更多正在做的事情,那么你想要实现的是,你没有一个if/else语句的堆栈,在那里执行依赖于传递给方法的对象的类型。

class SomeConsumer<T> where T : ISomeClass
{
    void SomeMethod(T t)
    {
        ISomeClass obj2 = (ISomeClass) t;
        // execute
        t.Operation();
    }
}

interface ISomeClass{
    void Operation();
}

class SomeClass : ISomeClass {
    public void Operation(){/*execute operation*/}
}
mum43rcc

mum43rcc4#

无意中发现了这个问题,并希望为以后发现这个问题的其他人提供一个更新的答案。在较新的C#版本中(在我写这篇文章时是8.0),pattern matching将允许您以一种更简洁的方式来完成这个任务:

void SomeMethod<T>(T t)
{
    switch(t)
    {
        case TypeA a:
            // Do some operation using a.
            Console.WriteLine($"{a} is a TypeA!");
            break;
        case TypeB b:
            // Do some operation using b.
            Console.WriteLine($"{b} is a TypeB!");
            break;
        default:
            // Handle this case.
            Console.WriteLine("I don't know what this type is.");
            break;
    }
}

这将检查对象的类型,如果找到匹配项,将在一个步骤中将其赋值给指定的变量,然后该变量就可以在case的主体中使用了。(您也可以在if语句中执行类似的操作:x1月1x)
尽管如此,我还是同意其他人的回答,即您应该尽可能地约束这个操作(void SomeMethod<T>(T t) where T : ISomeInterface {...}),或者如果可能的话,将操作移到您正在测试的类中。

s71maibg

s71maibg5#

对于这种情况,可以使用as

void SomeMethod(T t)
{
    SomeClass obj2 = t as SomeClass;
}
3npbholx

3npbholx6#

如果在输入类型T和目标类型TypeATypeB之间没有关系(使用参数约束),并且我们纯粹地查看强制转换问题,则答案很简单:

不,没有比您正在使用的方法更好的方法了!!!

我确实同意其他一些人的观点,如果你在那个物体上做更多的操作,你可能会想选择一个不同的设计。

rm5edbpk

rm5edbpk7#

我知道这是一个迟来的问题,但在这里你可以做什么
一个很好的选择是让您的函数接受类object的参数,并根据需要切换大小写
你只管选演员

YourClass = (YourClass) parameterObject;
vu8f3i0k

vu8f3i0k8#

这个简单的破解就能解决所有问题吗?:

public static TOut Cast<TOut, TIn>(TIn item) 
    {
        return Enumerable.Cast<TOut>(new[] { item }).First();
    }

是的,这样编译器就不会发现强制转换问题,我们创建的对象会使GC有点紧张,但它很容易编写和理解。
当然,你可以在Cast操作符的实现中复制你需要的位,但我猜大多数人不会理解代码的内容,所以如果你需要更高的性能,你可以得到更多,但在大多数情况下应该工作得很好。

0pizxfdo

0pizxfdo9#

我有一个继承自另一个类A的类B,Convert.ChangeType失败,并显示“Object must implementing IConvertible.”System.InvalidCastException.但我可以用不同的方法来做:

public classs ClassB : ClassA
{
    public string SomePropety { get; set; }
}

public class ClassA
{
    public string SomeField { get; set; }
}

public class SomeClass
{
   public T AGenericMethod<T>()
   {
       var retObj = SomeClassWithGeneric.SomeGenericMethod<T>();
       object obj = retObj;
       ClassA objA = (ClassA)obj;
       //Do stuff with objA....
       return  retObj;
   }
}

这里的诀窍是我先把变量retObj设置为一个对象变量,然后我可以把对象变量转换成我想要的基类。这比我想做的任何其他黑客都要容易和干净得多!
这对微软来说似乎很容易。

相关问题