具有已知类型但为空值的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.