c# 4.0引入了一种叫做“动态”的新类型。这听起来不错,但是程序员要用它来做什么呢?

在某种情况下,它是否可以挽救局面?


当前回答

用法示例:

你使用了许多具有共同属性'CreationDate'的类:

public class Contact
{
    // some properties

    public DateTime CreationDate { get; set; }        
}

public class Company
{
    // some properties

    public DateTime CreationDate { get; set; }
    
}

public class Opportunity
{
    // some properties

    public DateTime CreationDate { get; set; }
    
}

如果你写一个通用的方法来检索'CreationDate'属性的值,你必须使用反射:

static DateTime RetrieveValueOfCreationDate(Object item)
{
    return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
}

使用“动态”概念,你的代码会更加优雅:

static DateTime RetrieveValueOfCreationDate(dynamic item)
{
    return item.CreationDate;
}

其他回答

The best use case of dynamic type variables for me was when, recently, I was writing a data access layer in ADO.NET (using SQLDataReader) and the code was invoking the already written legacy stored procedures. There are hundreds of those legacy stored procedures containing bulk of the business logic. My data access layer needed to return some sort of structured data to the business logic layer, C# based, to do some manipulations (although there are almost none). Every stored procedure returns different set of data (table columns). So instead of creating dozens of classes or structs to hold the returned data and pass it to the BLL, I wrote the below code which looks quite elegant and neat.

public static dynamic GetSomeData(ParameterDTO dto)
        {
            dynamic result = null;
            string SPName = "a_legacy_stored_procedure";
            using (SqlConnection connection = new SqlConnection("my connection string"))
            {
                SqlCommand command = new SqlCommand(SPName, connection);
                command.CommandType = System.Data.CommandType.StoredProcedure;                
                command.Parameters.Add(new SqlParameter("@empid", dto.EmpID));
                command.Parameters.Add(new SqlParameter("@deptid", dto.DeptID));
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        dynamic row = new ExpandoObject();
                        row.EmpName = reader["EmpFullName"].ToString();
                        row.DeptName = reader["DeptName"].ToString();
                        row.AnotherColumn = reader["AnotherColumn"].ToString();                        
                        result = row;
                    }
                }
            }
            return result;
        }

你可以使用pythonnet调用动态语言,比如CPython:

充满活力。

在对泛型应用数值运算符时,可以将泛型强制转换为动态泛型。这提供了类型安全性并避免了泛型的限制。这本质上是*鸭子打字:

T y = x *(动态)x,其中typeof(x)为T

我很惊讶没有人提到多重调度。解决这个问题的通常方法是通过访问者模式,这并不总是可能的,所以你最终会得到堆叠的支票。

这是我自己的一个应用实例。而不是做:

public static MapDtoBase CreateDto(ChartItem item)
{
    if (item is ElevationPoint) return CreateDtoImpl((ElevationPoint)item);
    if (item is MapPoint) return CreateDtoImpl((MapPoint)item);
    if (item is MapPolyline) return CreateDtoImpl((MapPolyline)item);
    //other subtypes follow
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

你该怎么做:

public static MapDtoBase CreateDto(ChartItem item)
{
    return CreateDtoImpl(item as dynamic);
}

private static MapDtoBase CreateDtoImpl(ChartItem item)
{
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

private static MapDtoBase CreateDtoImpl(MapPoint item)
{
    return new MapPointDto(item);
}

private static MapDtoBase CreateDtoImpl(ElevationPoint item)
{
    return new ElevationDto(item);
}

注意,在第一种情况下,ElevationPoint是mappointment的子类,如果它没有放在mappointment之前,它将永远不会被到达。dynamic则不是这样,因为最接近的匹配方法将被调用。

正如您可能从代码中猜到的那样,当我执行从ChartItem对象到其可序列化版本的转换时,该特性非常方便。我不想用访问者污染我的代码,我也不想用无用的序列化特定属性污染我的ChartItem对象。

COM互操作。尤其是IUnknown。这是专门为它设计的。

用法示例:

你使用了许多具有共同属性'CreationDate'的类:

public class Contact
{
    // some properties

    public DateTime CreationDate { get; set; }        
}

public class Company
{
    // some properties

    public DateTime CreationDate { get; set; }
    
}

public class Opportunity
{
    // some properties

    public DateTime CreationDate { get; set; }
    
}

如果你写一个通用的方法来检索'CreationDate'属性的值,你必须使用反射:

static DateTime RetrieveValueOfCreationDate(Object item)
{
    return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
}

使用“动态”概念,你的代码会更加优雅:

static DateTime RetrieveValueOfCreationDate(dynamic item)
{
    return item.CreationDate;
}