Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET数据绑定包装器类的框架_C#_Asp.net_Data Binding_Dynamic_Proxy Classes - Fatal编程技术网

C# ASP.NET数据绑定包装器类的框架

C# ASP.NET数据绑定包装器类的框架,c#,asp.net,data-binding,dynamic,proxy-classes,C#,Asp.net,Data Binding,Dynamic,Proxy Classes,显然。大笨蛋,因为我看到这样的语法非常有用: public class User { public string FirstName { get; set; } public string LastName { get; set; } } ... // No this doesn't exist, I just wish it did! MyGrid.DataSource = GetAllUsers() .AsDynamic() .WithProper

显然。大笨蛋,因为我看到这样的语法非常有用:

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

...

// No this doesn't exist, I just wish it did!
MyGrid.DataSource = GetAllUsers()
    .AsDynamic()
        .WithProperty("FullName", user => user.FirstName + " " + user.LastName)
    .ToEnumerable(); // returns IEnumerable<dynamic>
MyGrid.DataBind()

...

<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="FullName" HeaderText="Full Name" />
公共类用户
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
}
...
//不,这不存在,我只是希望它存在!
MyGrid.DataSource=GetAllUsers()
.AsDynamic()
.WithProperty(“全名”,user=>user.FirstName+“”+user.LastName)
.ToEnumerable();//返回IEnumerable
MyGrid.DataBind()
...
)有效地向包装的数据对象添加属性。对FirstName和LastName的请求将由真实对象“服务”,而对FullName的请求将被路由到要动态计算的委托或表达式

这是一个简单的示例,因为在大多数情况下,您可以轻松地将FullName属性添加到用户对象,并且可以使用TemplatedField轻松完成此操作

但是,如果添加的属性很难在没有几行数据绑定代码的TemplatedField中实现,该怎么办?如果你没有控制用户类的源代码呢?或者,如果无法将属性添加到用户,因为其计算依赖于程序集,而程序集本身依赖于用户的程序集,该怎么办?(循环参考问题)

出于这个原因,最好有一个非常容易应用的数据绑定包装器,这样您就不必每次都生成一个全新的类

那么我到底想要什么呢?


有没有什么框架或技术支持这种事情?上面的确切语法并不重要,只需要能够动态地向类添加内容,并在数据绑定中使用这些代理,而无需大量手动管道代码。

您可能需要查看Clay库(请参阅):


当然,剥猫皮的方法不止一种,特别是在句法上。另外,我还没有深入研究它(这是你的工作!;),所以我不知道一个粘土对象是否可以粘到现有对象上,或者你是否需要像我一样从现有对象填充新的粘土用户。最重要的是,如果我没有看错这篇文章,如果你从一个接口继承它们,Clay对象生活在CLR中,获得Intellisense,就像真正的非动态对象一样工作。

实现这一点的一种方法是使用asp:TemplateField

也可以使用动态Linq来执行此操作,请参见

然后可以使用动态Linq创建语句的动态select部分。下面是一些用于创建select语句的代码,该语句选择所有基础对象的属性,并基于动态表达式创建额外的属性

public class ExtraProperty
{
    public string Name { get; set; }
    public string Expression { get; set; }
}


/// <summary>
/// Creates a string on the form "new (property1, property2, ..., expression1 as extraproperty1, ... )
/// </summary>
/// <param name="t"></param>
/// <param name="extraProperties"></param>
/// <returns></returns>
public string CreateSelectClauseWithProperty(Type objecType, ExtraProperty[] extraProperties)
{
    string ret = "new(";
    bool notFirst = false;
    System.Reflection.PropertyInfo[] typeProps = objecType.GetProperties();


    // Equivalent of "Select objectType.*"
    foreach (System.Reflection.PropertyInfo p in typeProps)
    {
        if (notFirst)
            ret += ",";
        else
            notFirst = true;
        ret += p.Name;
    }

    // Equivalent of "expression1 as name1, expression2 as name2, ..." - giving the extra columns
    foreach (ExtraProperty ep in extraProperties)
    {
        if (notFirst)
            ret += ",";
        else
            notFirst = true;
        ret += ep.Expression + " as " + ep.Name;
    }
    return ret + ")";
}

我找到了三种使用C#解决(某些)问题的方法,以及一种使用visualstudio工具扩展这些方法的方法

匿名类型 ASP.NET数据可以绑定到:

匿名类型仍然可以方便地访问原始类型(在本例中,通过
User
属性)。这将使数据绑定相对容易(使用
将方法“附加”到类,即使您无法访问类的源:

public static class UserExtensions
{
  public static string GetFullName(this User user)
  {
      return user.FirstName + " " + user.LastName;
  }
}
对于数据绑定,我们必须使用

,我研究了粘土,认为它不适合我所追求的东西。然而,粘土内部使用了,其中确实有一些有趣的东西,虽然不完美,但肯定接近我希望存在的东西

Castle DynamicProxy可以通过发出代码,然后拦截对对象的调用来创建对象的代理。关于业务对象的唯一要求是,方法和属性需要标记为
virtual
,以便Castle拦截对它们的调用

然后,您可以将“mixin”添加到代理对象中。我将用问题中的用户示例演示:

public class User
{
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}
如果我们想将FullName添加到此对象的代理,那么我们需要通过创建一个声明属性的接口,然后创建一个可以从现有用户提供值的实现对象来实现这一点:

public interface IUserProxy
{
    string FullName { get; }
}

public class UserProxyImpl : IUserProxy
{
    public User User { get; set; }

    public string FullName
    {
        get { return User.FirstName + " " + User.LastName; }
    }
}
现在对于数据绑定,我真的想在可枚举上使用它,这样扩展方法就可以完成创建代理和添加mixin的工作。我们将允许调用代码使用
Func
提供mixin(基本上只是对象),以便我们可以使用lambda表达式定义它们:

public static class ProxyExtensions
{
    public static IEnumerable<T> ProxyAddMixins<T>(this IEnumerable<T> collection, params Func<T, object>[] mixinSelectors)
        where T : class
    {
        ProxyGenerator factory = new ProxyGenerator();
        foreach (T item in collection)
        {
            ProxyGenerationOptions o = new ProxyGenerationOptions();
            foreach (var func in mixinSelectors)
            {
                object mixin = func(item);
                o.AddMixinInstance(mixin);
            }
            yield return factory.CreateClassProxyWithTarget<T>(item, o);
        }
    }
}
我真的很想通过定义一些lambda来创建代理,而不需要定义额外的接口或实现类,但这似乎是实现这一点的唯一方法。当然,与其他方法相比,您必须考虑是否真的值得发布这些自定义类型来完成这项工作


,所以您不必组装它来尝试。

我不明白为什么您不直接执行
MyGrid.DataSource.GetAllUsers().Select(u=>new{u.FirstName,u.LastName,FullName=u.FirstName+“”+u.LastName})
除了它能给你什么以外,你还需要什么?那会有用的,我已经做到了,但从本质上来说,必须映射“passthru”是很烦人的我想通过的每个用户属性的匿名类型上的属性。如果该类型有20多个属性呢?我不认为Clay库真的针对这种类型的目的,但我注意到它在引擎盖下使用Castle DynamicProxy,而且(虽然也不完美)正如我在自己的回答中所概述的那样,这表明了一些希望:所有伟大的建议,考虑到我真正想要的东西目前似乎并不存在。我认为T4的想法特别有价值。我可以看到添加属性>让代理工作得很好。
<%# Eval("User.FirstName") %>
<%# Eval("User.LastName") %>
<%# Eval("FullName") %>
<asp:BoundField DataField="FullName" />
public static class UserExtensions
{
  public static string GetFullName(this User user)
  {
      return user.FirstName + " " + user.LastName;
  }
}
<%# Eval("User.FirstName") %>
<%# Eval("User.LastName") %>
<%# (Container.DataItem as User).GetFullName() %>
public partial class User
{
    public string FullName
    {
        get { return this.FirstName + " " + this.LastName; }
    }
}
<asp:BoundField DataField="FirstName" />
<asp:BoundField DataField="LastName" />
<asp:BoundField DataField="FullName" />
DataGrid.DataSource = GetAllUsers().
  .AsQueryable()
  .Select(u => new UserViewModel(u));
DataGrid.DataBind()
<asp:BoundField DataField="FirstName" />
<asp:BoundField DataField="LastName" />
<asp:BoundField DataField="FullName" />
public class User
{
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}
public interface IUserProxy
{
    string FullName { get; }
}

public class UserProxyImpl : IUserProxy
{
    public User User { get; set; }

    public string FullName
    {
        get { return User.FirstName + " " + User.LastName; }
    }
}
public static class ProxyExtensions
{
    public static IEnumerable<T> ProxyAddMixins<T>(this IEnumerable<T> collection, params Func<T, object>[] mixinSelectors)
        where T : class
    {
        ProxyGenerator factory = new ProxyGenerator();
        foreach (T item in collection)
        {
            ProxyGenerationOptions o = new ProxyGenerationOptions();
            foreach (var func in mixinSelectors)
            {
                object mixin = func(item);
                o.AddMixinInstance(mixin);
            }
            yield return factory.CreateClassProxyWithTarget<T>(item, o);
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        List<User> users = new List<User>();
        users.Add(new User { FirstName = "John", LastName = "Doe" });
        users.Add(new User { FirstName = "Jane", LastName = "Doe" });

        var userProxies = users
            .ProxyAddMixins(u => new UserProxyImpl { User = u })
            .ToList();

        Console.WriteLine("First\tLast\tFull");
        foreach (var userProxy in userProxies)
        {
            Console.WriteLine("{0}\t{1}\t{2}",
                DataBinder.Eval(userProxy, "FirstName"),
                DataBinder.Eval(userProxy, "LastName"),
                DataBinder.Eval(userProxy, "FullName"));
        }
        Console.ReadLine();
    }
}