具有已知类型但为空值的BER。(我发现这对于将一组参数传递给SQL存储过程调用方非常有用,您可以从C#type中计算出SqlDbType类型,如果需要,该值仍然可以为null。)在ExpandoObject中,null是null是null,它不能有类型。(

具有已知类型但为空值的BER。(我发现这对于将一组参数传递给SQL存储过程调用方非常有用,您可以从C#type中计算出SqlDbType类型,如果需要,该值仍然可以为null。)在ExpandoObject中,null是null是null,它不能有类型。(,c#,.net,anonymous-types,C#,.net,Anonymous Types,具有已知类型但为空值的BER。(我发现这对于将一组参数传递给SQL存储过程调用方非常有用,您可以从C#type中计算出SqlDbType类型,如果需要,该值仍然可以为null。)在ExpandoObject中,null是null是null,它不能有类型。(当然,除非这个决定改变,否则我喜欢@Alex在这里给出的关于如何真正做到这一点的答案,当然你永远也不能把它投入到严肃的制作中。)我从来都不喜欢告诉人们“你不应该这么做”的答案.让我们假设,有时问问题的人有很好的理由想做某事,然后告诉他们是否可以


具有已知类型但为空值的BER。(我发现这对于将一组参数传递给SQL存储过程调用方非常有用,您可以从C#type中计算出
SqlDbType
类型,如果需要,该值仍然可以为null。)在
ExpandoObject
中,null是null是null,它不能有类型。(当然,除非这个决定改变,否则我喜欢@Alex在这里给出的关于如何真正做到这一点的答案,当然你永远也不能把它投入到严肃的制作中。)我从来都不喜欢告诉人们“你不应该这么做”的答案.让我们假设,有时问问题的人有很好的理由想做某事,然后告诉他们是否可以,而不是他们是否应该!(是的,99.9%的人永远都不需要这个,我同意。但也许你可以用它来做一些很酷的事情,比如说帮助编写一个更有用/简洁/易于编码的API,因为它在幕后使用它;然后我会说,如果VB和底层运行时允许你做一些基本上在C中被故意关闭的事情,那就太可惜了。)#.)是的,我也是。我喜欢探索并想出一些对某些人来说可能很奇怪的代码,但可能是一个奇怪场景的正确解决方案。探索可能性是很有趣的。这是一个很好的例子,说明了在所有情况下使用var如何使代码完全不可读。@Neutrino,说得对,但我不认为使用完整类型名称更可读。但是,我我创建了一个更完整、更清晰的示例,并使用了类型名称,以防其他人同意。
var output = new
{
    NetSessionId = string.Empty
};

foreach (var property in output.GetType().GetProperties())
{
    property.SetValue(output, "Test", null);
}
public static class AnonymousObjectMutator
{
    private const BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    private static readonly string[] BackingFieldFormats = { "<{0}>i__Field", "<{0}>" };

    public static T Set<T, TProperty>(
        this T instance,
        Expression<Func<T, TProperty>> propExpression,
        TProperty newValue) where T : class
    {
        var pi = (propExpression.Body as MemberExpression).Member;
        var backingFieldNames = BackingFieldFormats.Select(x => string.Format(x, pi.Name)).ToList();
        var fi = typeof(T)
            .GetFields(FieldFlags)
            .FirstOrDefault(f => backingFieldNames.Contains(f.Name));
        if (fi == null)
            throw new NotSupportedException(string.Format("Cannot find backing field for {0}", pi.Name));
        fi.SetValue(instance, newValue);
        return instance;
    }
}
public static void Main(params string[] args)
{
    var myAnonInstance = new { 
        FirstField = "Hello", 
        AnotherField = 30, 
    };
    Console.WriteLine(myAnonInstance);

    myAnonInstance
        .Set(x => x.FirstField, "Hello SO")
        .Set(x => x.AnotherField, 42);
    Console.WriteLine(myAnonInstance);
}
{ FirstField = Hello, AnotherField = 30 }
{ FirstField = Hello SO, AnotherField = 42 }
var people = new List<Person>
{
    new Person { FirstName = "John", LastName = "Doe" },
    new Person { FirstName = "Jane", LastName = "Doe" },
    new Person { FirstName = "Bob", LastName = "Saget" },
    new Person { FirstName = "William", LastName = "Drag" },
    new Person { FirstName = "Richard", LastName = "Johnson" },
    new Person { FirstName = "Robert", LastName = "Frost" }
};

// Method syntax.
var query = people.Select(p =>
{
    dynamic exp = new ExpandoObject();
    exp.FirstName = p.FirstName;
    exp.LastName = p.LastName;
    return exp;
}); // or people.Select(p => GetExpandoObject(p))

// Query syntax.
var query2 = from p in people
             select GetExpandoObject(p);

foreach (dynamic person in query2) // query2 or query
{
    person.FirstName = "Changed";
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

// Used with the query syntax in this example, but may also be used 
// with the method syntax just as easily.
private ExpandoObject GetExpandoObject(Person p)
{
    dynamic exp = new ExpandoObject();
    exp.FirstName = p.FirstName;
    exp.LastName = p.LastName;
    return exp;
}
    public T AssignErrorMessage<T>(T response, string errorDescription, int errorCode)
    {
        PropertyInfo ErrorMessagesProperty = response.GetType().GetProperty("ErrorMessage");
        if (ErrorMessagesProperty.GetValue(response, null) == null)
            ErrorMessagesProperty.SetValue(response, new ErrorMessage());

        PropertyInfo ErrorCodeProperty = ErrorMessagesProperty.GetType().GetProperty("code");
        ErrorCodeProperty.SetValue(response, errorCode);

        PropertyInfo ErrorMessageDescription = ErrorMessagesProperty.GetType().GetProperty("description");
        ErrorMessageDescription.SetValue(response, errorDescription);

        return response;
    }

    public class ErrorMessage
    {
        public int code { get; set; }
        public string description { get; set; }
    }
class Program
{
    static void Main(string[] args)
    {
        // Create a template that defines the anonymous type properties.
        var personTemplate = new { Name = "", Age = 0 };

        var sam = CreateFromAnonymousTemplate(personTemplate, "Sam", 43);
        var sally = CreateFromAnonymousTemplate(personTemplate, "Sally", 24);
    }

    private static Dictionary<Type, ConstructorInfo> _constructors = new Dictionary<Type, ConstructorInfo>();

    // By using T, we get intellisense for our returned objects.
    static T CreateFromAnonymousTemplate<T>(T templateReference, params object[] propertyValues)
    {
        // This is the type of the template. In this case, the anonymous type.
        Type anonymousType = templateReference.GetType();

        ConstructorInfo anonymousTypeConstructor;

        if (_constructors.ContainsKey(anonymousType))
        {
            anonymousTypeConstructor = _constructors[anonymousType];

            if(anonymousTypeConstructor.GetParameters().Length != propertyValues.Length)
                throw new ArgumentException("Invalid initialisation properties. Parameters must match type and order of type constructor.", "propertyValues");
        }
        else
        {
            PropertyInfo[] properties = anonymousType.GetProperties();
            if (properties.Count() != propertyValues.Length)
                throw new ArgumentException("Invalid initialisation properties. Parameters must match type and order of type constructor.", "propertyValues");

            // Retrieve the property types in order to find the correct constructor (which is the one with all properties as parameters).
            Type[] propertyTypes = properties.Select(p => p.PropertyType).ToArray();

            // The constructor has parameters for each property on the type.
            anonymousTypeConstructor = anonymousType.GetConstructor(propertyTypes);

            // We cache the constructor to avoid the overhead of creating it with reflection in the future.
            _constructors.Add(anonymousType, anonymousTypeConstructor);
        }

        return (T)anonymousTypeConstructor.Invoke(propertyValues);
    }
}
var dude = new { Name = "Bob", Age = 23 };
internal class AnonymousGeneratedTypeName
{

    private string name; // Actual field name is irrelevant
    private int    age;  // Actual field name is irrelevant

    public AnonymousGeneratedTypeName(string name, int age)
    {
        this.name = name; this.age = age;
    }

    public string Name { get { return name; } }

    public int    Age  { get { return age;  } }

    // The Equals and GetHashCode methods are overriden...
    // The ToString method is also overriden.

}
...

var dude = AnonymousGeneratedTypeName ("Bob", 23);
var dude = new { Name = "Bob", Age = 23 };
dynamic dude = new { Name = "Bob", Age = 23 };

dude.Name = "John"; // Compiles correctly.