是否可以在方法中获取调用实例?

时间:2016-04-07 17:39:20

标签: c# asp.net

我想这样做的一般原因是:

class MovieApiController : ApiController
{
    public string CurrentUser {get;set;}

    // ...

    public string Index()
    {
        return Resources.GetText("Color");
    }
}


class Resources
{
    static string GetText(string id)
    {
        var caller = ??? as MovieApiController;
        if (caller && caller.CurrentUser == "Bob")
        {
            return "Red";
        }
        else
        {
            return "Blue";
        }
    }
}

我不需要这是100%可靠的。似乎callstack应该有这些信息,但是StackFrame似乎没有公开任何关于每个帧执行的特定对象的信息。

4 个答案:

答案 0 :(得分:2)

一种方法试图嗅探"通常是一个坏主意。它的周围环境,根据谁打电话产生不同的结果。

更好的方法是让您的Resources班级了解其做出决定时需要了解的内容,并在知道所有相关信息的地方进行配置,例如

class MovieApiController : ApiController {
    private string currentUser;
    private Resources resources;
    public string CurrentUser {
        get {
            return currentUser;
        }
        set {
            currentUser = value;
            resources = new Resources(currentUser);
        }
    }
    // ...

    public string Index() {
        return resources.GetText("Color");
    }
}

class Resources {
    private string currentUser;
    public Resources(string currentUser) {
        this.currentUser = currentUser;
    }
    public string GetText(string id) {
        if (currentUser == "Bob") {
            return "Red";
        } else {
            return "Blue";
        }
    }
}

答案 1 :(得分:1)

CurrentUser应该在HttpContext.Current.User处可用,您可以将控制器从资源类中删除。

答案 2 :(得分:0)

  

似乎callstack应该有这个信息,

为什么呢?调用堆栈指示调用方法以获取您所在的位置 - 它没有关于实例的任何信息。

重新考虑您的参数,决定该方法需要哪些信息来完成其工作。到达课外(例如,通过使用callstack或利用HttpContext.Current等静态方法)限制了代码的可重用性。

根据您显示的内容,您只需要当前用户名(您甚至不会显示使用id值的位置。如果您想根据传入的内容返回不同的内容,那么可能你需要单独的方法吗?

作为旁注,优化器在重新组织代码方面具有很大的自由度,使其更有效,因此无法保证调用堆栈甚至包含您认为应该从源代码中提供的内容。

答案 3 :(得分:0)

简短回答 - 您不能创建一个自定义控制器工厂,将当前控制器存储为当前HttpContext的属性,甚至可能无法预测。

但是,通过尝试检查其调用者,一个类的行为方式确实不好。当一个方法依赖于另一个类时,它需要通过依赖正确的类,调用正确的方法并传递正确的参数来获得正确的行为。

所以在这种情况下你可以

  • 有一个传递给GetResources的参数,告诉它需要知道什么才能返回正确的字符串。
  • 创建一个更具体的Resources类,以满足您的需要
  • 声明

    public interface IResources
    {
        string GetText(string id);
    }
    

并且有多个实现IResources的类,使用依赖注入为该控制器提供正确的实现。理想情况下,这是最好的方案。 MovieApiControllerIResources的实施一无所知。它只知道有一个IResources的实例可以满足它的需要。并且Resource类对调用它的内容一无所知。无论什么叫它,它的行为都是一样的。

看起来像这样:

public class MovieApiController : ApiController
{
    private readonly IResources _resources;

    public MovieApiController(IResources resources)
    {
        _resources = resources;
    }

    public string Index()
    {
        return _resources.GetText("Color");
    }
}

注意控制器对Resources类没有任何了解。它只知道它有一些实现IResources并且它使用它的东西。

如果您使用的是ASP.NET Core,则依赖注入为built in。 (关于一般概念,有一些很好的阅读。)如果你使用的是旧的,那么你仍然可以添加它。

http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection - 这张图片的概念价值1000字。 http://www.c-sharpcorner.com/UploadFile/dacca2/implement-ioc-using-unity-in-mvc-5/

其中一些建议首先理解“控制反转”。您可能会发现根据示例实现某些内容更容易,而不首先尝试理解它。当你看到它的作用时,就会有这种理解。