如何将 Activator.CreateInstance 返回的对象转换为它转换的类型?

发布于 2024-11-02 22:57:19 字数 431 浏览 0 评论 0 原文

在下面的代码中,是否可以将 x 转换为您传递给 Activator.CreateInstance 的类型,而无需提前知道它是什么?我尝试传入 typeof... 但这不起作用。

var testClasses = AppDomain.CurrentDomain.GetAssemblies()
                  .Single(a=>a.FullName.StartsWith("VerifyStuff")).GetTypes()
                  .Where(t=>t.UnderlyingSystemType.Name.StartsWith("VerifyXXX"));

var x = Activator.CreateInstance(testClasses.ElementAt(0));

谢谢!

In the code below, is it possible to convert x to the type you're passing into Activator.CreateInstance without knowing what it is ahead of time? I tried passing in typeof...but that doesn't work.

var testClasses = AppDomain.CurrentDomain.GetAssemblies()
                  .Single(a=>a.FullName.StartsWith("VerifyStuff")).GetTypes()
                  .Where(t=>t.UnderlyingSystemType.Name.StartsWith("VerifyXXX"));

var x = Activator.CreateInstance(testClasses.ElementAt(0));

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼波传意 2024-11-09 22:57:19

您只需要对其进行强制转换:

MyObject x = (MyObject) Activator.CreateInstance(testClasses.ElementAt(0));

当然,如果您在 testClasses 中拥有一系列类型,这当然会更加困难。如果它们都派生自相同的基类或实现相同的接口,那么您可以转换为该基类或接口。

编辑:

是否可以将 x 转换为您传递给 Activator.CreateInstance 的类型而不提前知道它是什么?

只是为了更具解释性: x is 是您传递给 CreateInstance 的类型,但它被转换为对象,因为 CreateInstance不知道你会扔什么给它。您的问题发生在您创建具体实例之后 - 您无法将其传递到另一个(强类型)函数,因为您将其作为对象。有几种方法可以解决这个问题:

  • 正如我上面提到的,让它们全部派生自相同的基类或接口,以便您可以将它们作为基类或接口类型传递

  • 如果您有一个需要对这些具体实例执行操作的函数,请创建一个泛型函数来做到这一点:

    <前><代码>
    公共 T MyFunc(T myConcreteInstance)
    {
    ……做我需要做的一切……
    }

  • 这很丑陋,但可能很难避免...使用一个大的 if..else if 语句,用于在对它们进行操作之前确定它们的类型(提示:避免使用上面的选项 #1...):

    <前><代码>
    类型 t = myConcreteInstance.GetType();
    if (t == typeof(someType1))
    {

    }
    否则 if (t == typeof(someType2))
    {

    }
    ... ETC ...

如果此时您正在想“为什么我不只制作一个通用版本的 CreateInstance()?”那么就不用担心 - 那里已经是一个了,它仍然不能解决你在传递之前强类型化的问题他们周围。引用MSDN:

一般来说,CreateInstance 在应用程序代码中没有用处,因为类型必须在编译时已知。如果类型在编译时已知,则可以使用正常的实例化语法(C# 中的 new 运算符、Visual Basic 中的 New、C++ 中的 gcnew)。

如果您打算使用 CreateInstance,那是因为您提前不知道类型,因此您必须解决它。

You simply need to cast it:

MyObject x = (MyObject) Activator.CreateInstance(testClasses.ElementAt(0));

of course this is going to be more difficult if you have a whole range of types in testClasses. If they are all derived from the same base class or implement the same interface then you can cast to that base class or interface.

Edit:

is it possible to convert x to the type you're passing into Activator.CreateInstance without knowing what it is ahead of time?

just to be a little more explanatory: x is of the type you passed in to CreateInstance, but it is cast as an object, because CreateInstance has no idea what you may throw at it. You problem occurs after you've created your concrete instance - you can't pass it into another (strongly typed) function because you have it as an object. There are a couple of ways around this:

  • as i mentioned above, have them all derive from the same base class or interface, so that you can pass them around as that base class or interface type

  • if you have a function that needs to perform an operation on those concrete instances, create a generic function to do it:

    
    public T MyFunc(T myConcreteInstance) 
    {
        ... do whatever it is i need to do...
    }
    
  • this is ugly, but it may be difficult to avoid... use a big if..else if statement to determine their types before operating on them (hint: to avoid this use option #1 above...):

    
    Type t = myConcreteInstance.GetType();
    if (t == typeof(someType1))
    {
    
    }
    else if (t == typeof(someType2))
    {
    
    }
    ... etc ...
    

If at this point you are thinking "why don't i just make a generic version of CreateInstance()?" then don't bother - there already is one, it still doesn't solve your issue of having things strongly typed before passing them around. To quote MSDN:

In general, there is no use for the CreateInstance in application code, because the type must be known at compile time. If the type is known at compile time, normal instantiation syntax can be used (new operator in C#, New in Visual Basic, gcnew in C++).

If you are going to use CreateInstance, it's because you don't know the type ahead of time, therefore you must work around it.

捶死心动 2024-11-09 22:57:19

来自@slugster的回答:

如果您要使用CreateInstance,那是因为您事先不知道类型,因此您必须解决它。

对于阅读本文的人来说,可以采用替代策略:

var x = Activator.CreateInstance(testClasses.ElementAt(0));

并确定类型:

Type t = myConcreteInstance.GetType();
if (t == typeof(someType1))
{

}
else if (t == typeof(someType2))
{

}

在我的情况下,我正在使用 Mediatr &我无法将 TResponse 转换为具体实现,而是求助于通用接口。在此示例中,我展示了一个 ICommonResult,所有 Generic CommonResult实现作为 TResponse 传入的。这是绕过长 if、elseifswitch 类型检查的方法,例如:

protected override void Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state)
{
    // Keep a look out, there's only one example on the internet including GitHub Search: https://cs.github.com/?scopeName=All+repos&scope=&q=language%3Acsharp+%22Handle%28TRequest+request%2C+TException+exception%2C+RequestExceptionHandlerState%3CTResponse%3E+state%29%22
    // and my code here is way better than the one other example: https://github.com/paulopiriquito/SampleMediator/blob/915e82ac249b6e366df030c9f8456a6d809c2353/Behaviours/RequestExceptionHandler.cs?q=language%3Acsharp+%22Handle%28TRequest+request%2C+TException+exception%2C+RequestExceptionHandlerState%3CTResponse%3E+state%29%22 

    var response = Activator.CreateInstance<TResponse>() as ICommonResult;

    // PII Protection
    Redactor.Redact(request!);

    var pairs = JObject.FromObject(request)
    .Descendants()
    .OfType<JProperty>()
    .Where(p => p.Value is JValue)
    .Select(p => p.Name + ":" + p.Value);

    string requestNameAndArgsWithValues = $"{typeof(TRequest).Name}({string.Join(",", pairs)})";

    if (response != null)
    {
        response.AddError(ExceptionHelper.GetCommonErrorFromException(exception));
        response.IsException = true;
    }

    _logger.LogCritical($"Description: Exception handler Method: {requestNameAndArgsWithValues} Errors: {commonError.Description} User: {_userService.ToString()}");

    );

    state.SetHandled((TResponse)response!);
}}

接口:

public interface ICommonResult
{
    public bool IsSuccess { get; }
    public bool IsException { get; set; }
    void AddError(CommonError commonError);
}

From @slugster's answer:

If you are going to use CreateInstance, it's because you don't know the type ahead of time, therefore you must work around it.

For people reading this an alternative strategy to this:

var x = Activator.CreateInstance(testClasses.ElementAt(0));

and working out the type:

Type t = myConcreteInstance.GetType();
if (t == typeof(someType1))
{

}
else if (t == typeof(someType2))
{

}

In my situation I'm using Mediatr & I can't Cast the TResponse to a concrete implementation, instead I resort to a common Interface. In this example I show a ICommonResult that all Generic CommonResult<T's> implement that are passed in as the TResponse. This is how you can get around a long if, elseif or switch type check, eg:

protected override void Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state)
{
    // Keep a look out, there's only one example on the internet including GitHub Search: https://cs.github.com/?scopeName=All+repos&scope=&q=language%3Acsharp+%22Handle%28TRequest+request%2C+TException+exception%2C+RequestExceptionHandlerState%3CTResponse%3E+state%29%22
    // and my code here is way better than the one other example: https://github.com/paulopiriquito/SampleMediator/blob/915e82ac249b6e366df030c9f8456a6d809c2353/Behaviours/RequestExceptionHandler.cs?q=language%3Acsharp+%22Handle%28TRequest+request%2C+TException+exception%2C+RequestExceptionHandlerState%3CTResponse%3E+state%29%22 

    var response = Activator.CreateInstance<TResponse>() as ICommonResult;

    // PII Protection
    Redactor.Redact(request!);

    var pairs = JObject.FromObject(request)
    .Descendants()
    .OfType<JProperty>()
    .Where(p => p.Value is JValue)
    .Select(p => p.Name + ":" + p.Value);

    string requestNameAndArgsWithValues = 
quot;{typeof(TRequest).Name}({string.Join(",", pairs)})";

    if (response != null)
    {
        response.AddError(ExceptionHelper.GetCommonErrorFromException(exception));
        response.IsException = true;
    }

    _logger.LogCritical(
quot;Description: Exception handler Method: {requestNameAndArgsWithValues} Errors: {commonError.Description} User: {_userService.ToString()}");

    );

    state.SetHandled((TResponse)response!);
}}

The Interface:

public interface ICommonResult
{
    public bool IsSuccess { get; }
    public bool IsException { get; set; }
    void AddError(CommonError commonError);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文