如何将对象转换为其实际类型?

168

如果我有:

void MyMethod(Object obj) {   ...   }

我应该如何将obj转换为其实际类型?


3
编译时是否已知类型? - psubsee2003
3
你希望通过这个做什么?请告诉我们你想要达到什么目的,而不是你期望如何去实现它。 - Jon Skeet
@JonSkeet:我想能够从对象中调用一个函数。目前 obj.MyFunction(); 无法编译,尽管我知道真正的对象确实有这个函数。 - Paul Lassiter
4
如果你不知道类型,那么声明 MyFunction 方法的是什么? - Jon Skeet
1
如果你想在这个对象上调用一个方法,为什么不实现一个接口并在你的方法MyMethod(IMyinterface obj)中调用它呢? - Hassan Boutougha
显示剩余2条评论
11个回答

250

如果您知道实际类型,那么只需:

SomeType typed = (SomeType)obj;
typed.MyFunction();

如果你不知道实际的类型,那么 :不太行。你需要使用以下其中之一:

  • 反射(reflection)
  • 实现一个众所周知的接口
  • 动态(dynamic)

例如:

// reflection
obj.GetType().GetMethod("MyFunction").Invoke(obj, null);

// interface
IFoo foo = (IFoo)obj; // where SomeType : IFoo and IFoo declares MyFunction
foo.MyFunction();

// dynamic
dynamic d = obj;
d.MyFunction();

1
在Swift中等价的语法是什么? - Nagendra Rao
1
没事了,我找到了 as 进行类型转换和 type(of: ClassName) 函数来检查实例类型。 - Nagendra Rao

59

我认为你不能这样做(没有反射的情况下),你还需要给你的函数提供一个类型:

void MyMethod(Object obj, Type t)
{
    var convertedObject = Convert.ChangeType(obj, t);
    ...
}

更新:

这可能适用于您:

void MyMethod(Object obj)
{
    if (obj is A)
    {
        A a = obj as A;
        ...
    } 
    else if (obj is B)
    {
        B b = obj as B;
        ...
    }
}

9
对于类型为object的对象进行反射,将不能得到该对象的“实际类型”,这是问题提出者所问的。此外,你的MyMethod逻辑有缺陷,因为obj既可以是A类型,也可以是B类型。你的逻辑并没有提供“实际类型”(正如问题提出者所要求的那样),它只提供了一个兼容的类型,而且不一定是期望的类型。 - Jazimov
1
使用 obj.GetType()。这将确实返回它的实际类型。 - JSON
我们已经知道了“类型”。他希望它解析为像“T”一样的东西。 - Latency

11
如何呢?
JsonConvert.DeserializeObject<SomeType>(object.ToString());

@user12637955 这实际上是一个可行的答案,但由于装箱和拆箱的存在,它具有更大的复杂性,即对象 -> ToString() -> 具体类型。为了更准确,它应该像这样:var myType = JsonConvert.DeserializeObject<MyType>(object.ToString()); - Coke

3
您也可以使用模式匹配
void MyMethod(Object obj) {   

  if(obj is SomeType myVar){
    myVar.MyFunction();
  }
}

1
如果您的MyFunction()方法只在一个类(及其派生类)中定义,请尝试
void MyMethod(Object obj) 
{
    var o = obj as MyClass;
    if (o != null)
        o.MyFunction();
}

如果您在定义要调用的函数的不相关类中有大量代码,那么您应该定义一个接口,并使您的类定义该接口:
interface IMyInterface
{
    void MyFunction();
}

void MyMethod(Object obj) 
{
    var o = obj as IMyInterface;
    if (o != null)
        o.MyFunction();
}

1

另一个选择是将其序列化,然后将其反序列化为您想要的对象。 JsonConvert.DeserializeObject<OtherType>(JsonConvert.SerializeObject(obj));


1
在我的情况下,AutoMapper运作良好。
AutoMapper可以映射到/从动态对象,而无需任何显式配置:
public class Foo {
    public int Bar { get; set; }
    public int Baz { get; set; }
}
dynamic foo = new MyDynamicObject();
foo.Bar = 5;
foo.Baz = 6;

Mapper.Initialize(cfg => {});

var result = Mapper.Map<Foo>(foo);
result.Bar.ShouldEqual(5);
result.Baz.ShouldEqual(6);

dynamic foo2 = Mapper.Map<MyDynamicObject>(result);
foo2.Bar.ShouldEqual(5);
foo2.Baz.ShouldEqual(6);

同样地,您可以从字典直接映射到对象,AutoMapper将把键与属性名称对齐。
更多信息请参见https://github.com/AutoMapper/AutoMapper/wiki/Dynamic-and-ExpandoObject-Mapping

0

如果您知道类型,可以将其转换为实际类型,例如它是从名为abc的类中派生的。 您可以这样调用函数:

(abc)(obj)).MyFunction();

如果您不知道该函数如何实现,可以用另一种方式来完成。这并不总是容易的,但您可以通过其签名找到它的某些方法。如果您遇到这种情况,请告诉我们。


0
如果可能有多种类型,方法本身不知道要转换的类型,但调用者知道,你可以使用类似这样的代码:
void TheObliviousHelperMethod<T>(object obj) {
    (T)obj.ThatClassMethodYouWantedToInvoke();
}

// Meanwhile, where the method is called:
TheObliviousHelperMethod<ActualType>(obj);

可以在圆括号后使用 where 关键字添加类型限制。


-2
Implement an interface to call your function in your method
interface IMyInterface
{
 void MyinterfaceMethod();
}

IMyInterface MyObj = obj as IMyInterface;
if ( MyObj != null)
{
MyMethod(IMyInterface MyObj );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接