【问题标题】:dynamically set value to the parameter of function attribute in C#在C#中为函数属性的参数动态设置值
【发布时间】:2013-07-04 09:22:05
【问题描述】:

我在使用 Linq DataContext 从数据库获取数据列表时遇到问题

我正在尝试以下代码

公共类 DBContextNew : DataContext {

    public static string StoreProcedureName = "";

    [Function(Name = StoreProcedureName, IsComposable = false)]
    public ISingleResult<T> getCustomerAll()
    {

        IExecuteResult objResult =
          this.ExecuteMethodCall(this, (MethodInfo)(MethodInfo.GetCurrentMethod()));

        ISingleResult<T> objresults =
            (ISingleResult<T>)objResult.ReturnValue;
        return objresults;
    }


}

但遇到错误

[Function(Name = StoreProcedureName, IsComposable = false)]

as 属性参数必须是常量表达式,typeof 属性参数类型的表达式或数组创建表达式

我想在运行时将值传递给 Name 属性。

有可能吗?

请帮忙。

【问题讨论】:

  • 不可能,运行时不能传递Attributes参数
  • 经过深思熟虑是可能的。但是你必须知道运行时的反射会导致性能问题,所以你必须尽一切努力在没有它的情况下生存。当您在项目启动或一些单例初始化时做某事时,反射是很好的。
  • 忘记将动态数据传递给属性,告诉我们您将尝试实现什么,我们会尽力帮助您修复没有属性的问题。
  • @Maris:我正在尝试创建一个从存储过程返回表数据的通用函数。并且该数据将被转换为给定的模板类型列表,即 T. 因为我想使用变量传递不同的存储过程名称。

标签: c# asp.net sql linq-to-sql


【解决方案1】:

问题是:

 public static string StoreProcedureName = "";

你需要让它成为一个常数。

public const string StoreProcedureName = "";

编译器会在错误消息中告诉你这一点(它必须是一个常量表达式)。

【讨论】:

  • 谢谢,但我想在运行时为 StoreProcedureName 赋值,所以它不适合我。
  • @NileshNikumbh - 我认为你不能在运行时传递它们。我遇到过类似的问题,
【解决方案2】:

很遗憾,您不能为属性声明提供动态值(如变量的内容)。

但是您可以在运行时更改属性的值:

public class TestAttribute : Attribute
{ public string Bar { get; set; } }

public class TestClass
{
    [Test]
    public string Foo()
    { return string.Empty; }
}

然后改变这个值:

var method = typeof(TestClass).GetMethod("Foo");
var attribute = method.GetCustomAttribute(typeof(TestAttribute)) as TestAttribute;
attribute.Bar = "Hello";

请记住,您的类的所有实例都共享属性。

【讨论】:

  • 你必须记住这会导致多线程问题。
【解决方案3】:

在简单属性上使用城堡动态代理。因为用属性来做这将迫使你在运行时使用反射来改变属性参数中的一些东西。这样,像user1908061 建议会导致2个问题:

1) 性能问题。在运行时调用存储过程对于应用程序的性能来说非常“重量级” 2)多线程问题。假设有 2 个线程以 10 个滴答的间隔调用此代码

var method = typeof(TestClass).GetMethod("Foo");
var attribute = method.GetCustomAttribute(typeof(TestAttribute)) as TestAttribute;
attribute.Bar = "Hello";

Thread1 会将Bar 参数的属性更改为“Hello”,此时Thread2 将访问相同的代码并将Bar 参数更改为其他值,这将导致问题。让我们看一下时间轴:

 0 ticks - Thread1 started to work, accessed the property of TestAttribute and made the Bar param = "Hello"
 20 ticks - Thread2 started to work, accessed the property of TestAttribute and made the Bar param = "SomeOtherValue"
 40 ticks - You are expecting that you will call function with `Bar`=="Hello", but it's getting called with the `Bar`=="SomeOtherValue"
 60 ticks - Thread2 getting called with `Bar`=="SomeOtherValue"

所以你的 Thread1 会得到错误的结果。

所以我建议使用 CastleDynamicProxy 来做你想做的事。有了它,您可以在方法之前运行一些代码并替换方法的结果,也可以在方法之后运行一些代码。这种方式将在运行时工作。

还有一项技术 - PostSharp 会做同样的事情,但会以另一种方式。这将在编译时工作。

【讨论】:

  • 显然你可以在属性设置器中添加一个锁来避免线程问题。
  • 是的。这将解决部分问题。但是让我们想象一下,您有 1000000 个线程正在运行并尝试访问此方法,但由于Bar 已锁定,它们无法访问。这会带来更多的问题。过程会更加不可控。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-02
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多