Imagine that you want to declare an object with an anonymous type, but you need it to be generic (I can't think of an actual reason why, this is theoretical). How would you create such an object?
For example:
var anonymousGeneric = new <T>{ }; // <- doesn't work
var anonymousGeneric = Activator.CreateInstance((new { }).GetType()); // Not generic
edit:
// because:
(new { }).GetType().IsGenericType == false
// Of course, any useful anonymous object _will_ be generic:
(new { a="b" }).GetType().IsGenericType == true
// But in the process of testing various aspects of this question
// it had never occurred to me that I needed to supply any property
// (this was all theoretical, remember)
end edit
But neither of those works. Of course, the real-world solution to this imagined problem is to define an actual class definition:
public GenericThing<T> { }
But that isn't anonymous like above.
Once the object is created, imagine using it later on with something like:
var anonymousGenericType = anonymousGeneric.GetType();
// These throw exception
// <>f__AnonymousType0#1 is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true.
// + System.RuntimeType.MakeGenericType(System.Type[])
var intThing = anonymousGenericType.MakeGenericType(typeof(int));
var stringThing = anonymousGenericType.MakeGenericType(typeof(string));
In summary, is it possible to create an anonymous generic object?
(I can't think of an actual reason why, this is theoretical)
In that case, let's stick with the simple and obvious, since it's easier to find a reason: simply create a regular anonymous object from a generic method.
public object Foo<T>(T t) { return new { t }; }
Here, Foo(0) and Foo("") will necessarily return different types, but they'll still share a type definition.
Pretty much any use of anonymous types can make equal sense inside a generic method.
anonymousGeneric.GetType() is returning the wrong type of generic type: Closed (with type parameter(s)) vs open (without)1. If you want to change a type parameter, you need to get the generic type definition from it.
The following actually works, though I can't imagine what good it does anybody 2:
var anonymousGeneric = new {a = "b"};
var anonymousGenericType = anonymousGeneric.GetType().GetGenericTypeDefinition();
var intThingType = anonymousGenericType.MakeGenericType(typeof(int));
var intThingInstance = Activator.CreateInstance(intThingType, 9);
Now we have a thing just like anonymousGeneric, but its type parameter is int instead of string, and its a property is 9. But what's it good for? How do you declare a reference to it? You could bind to its properties in XAML, if you had some time on your hands.
1 Thanks to Amy and Servy for pitching in to clear up my confusion with terminology.
2 Note that there are more things in heaven and earth than are dreamt of in my philosophy.
Related
I know there are a lot of questions about C# anonymous types, but none of them answers me. I also know that you can return anonymous types, either assigning the result of the method to a dynamic object or casting it as this article by Jon Skeet states, but in both cases you need to know which are the members of the anonymous object, so why can't we have a sort of keyword named anonymous which allow us to do things like this:
anonymous F()
{
...
return new { a = 5, b = "some string" };
}
and then using it like this:
anonymous a = F();
but having static typing?
I mean, why isn't the compiler able to know statically which are the members of the anonymous object F method returns, and so give me intellisense?
What would you stop than from doing something like this:
anonymous F()
{
if (something) return new { a = 5 };
else return new { b = 1, z = "asdf" };
}
How is compiler supposed to know which type is returned then? Should it limit you at design time with error messages that those anonymous types are not the same? Is it worth the effort? You can use dynamic for such cases or create actual classes if needed - to make code clear.
I'm generating code in a visual studio extension using CodeDom and plain code strings. My extension reads a current classes declared fields and properties using reflection and generates contructors, initializers, implements certain interfaces, etc.
The generator class is simple:
public class CodeGenerator < T >
{
public string GetCode ()
{
string code = "";
T type = typeof(T);
List < PropertyInfo > properties = t.GetProperties();
foreach (PropertyInfo property in properties)
code += "this." + property.Name + " = default(" + property.PropertyType.Name + ")";
}
}
I'm stuck at field and property initializers in two ways.
Firstly, although default(AnyNonGenericValueOrReferenceType) seems to work in most cases, I'm uncomfortable with using it in generated code.
Secondly, it does not work for generic types since I can't find a way to get the underlying type of the generic type. So if a property is List < int >, property.PropertyType.Name returns List`1. There are two problems here. First, I need to get the proper name for the generic type without using string manipulation. Second, I need to access the underlying type. The full property type name returns something like:
System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Before I try to answer, I feel compelled to point out that what you're doing seems redundant. Assuming that you are putting this code into a constructor, generating something like:
public class Foo
{
private int a;
private bool b;
private SomeType c;
public Foo()
{
this.a = default(int);
this.b = default(bool);
this.c = default(SomeType);
}
}
is unnecessary. That already happens automatically when a class is constructed. (In fact, some quick testing shows that these assignments aren't even optimized away if they're done explicitly in the constructor, though I suppose the JITter could take care of that.)
Second, the default keyword was designed in large part to do exactly what you're doing: to provide a way to assign the "default" value to a variable whose type is unknown at compile time. It was introduced for use by generic code, I assume, but auto-generated code is certainly correct in using it as well.
Keep in mind that the default value of a reference type is null, so
this.list = default(List<int>);
does not construct a new List<int>, it just sets this.list to null. What I suspect you want to do, instead, is to use the Type.IsValueType property to leave value types at their default values, and initialize reference types using new.
Lastly, I think what you're looking for here is the IsGenericType property of the Type class and the corresponding GetGenericArguments() method:
foreach (PropertyInfo property in properties)
{
if (property.Type.IsGenericType)
{
var subtypes = property.Type.GetGenericArguments();
// construct full type name from type and subtypes.
}
else
{
code += "this." + property.Name + " = default(" + property.PropertyType.Name + ")";
}
}
EDIT:
As far as constructing something useful for a reference type, a common technique I've seen used by generated code is to require a parameterless constructor for any class that you expect to use. It's easy enough to see if a class has a parameterless constructor, by calling Type.GetConstructor(), passing in an empty Type[] (e.g. Type.EmptyTypes), and see if it returns a ConstructorInfo or null. Once that has been established, simply replacing default(typename) with new typename() should achieve what you need.
More generally you can supply any array of types to that method to see if there's a matching constructor, or call GetConstructors() to get them all. Things to look out for here are the IsPublic, IsStatic, and IsGenericMethod fields of the ConstructorInfo, to find one you can actually call from wherever this code is being generated.
The problem you are trying to solve, though, is going to become arbitrarily complex unless you can place some constraints on it. One option would be to find an arbitrary constructor and build a call that looks like this:
var line = "this." + fieldName + " = new(";
foreach ( var param in constructor.GetParameters() )
{
line += "default(" + param.ParameterType.Name + "),";
}
line = line.TrimEnd(',') + ");"
(Note this is for illustrative purposes only, I'd probably use CodeDOM here, or at least a StringBuilder :)
But of course, now you have the problem of determining the appropriate type name for each parameter, which themselves could be generics. And the reference type parameters would all be initialized to null. And there's no way of knowing which of the arbitrarily many constructors you can pick from actually produces a usable object (some of them may do bad things, like assume you're going to set properties or call methods immediately after you construct an instance.)
How you go about solving those issues is not a technical one: you can recursively apply this same logic to each parameter as far down as you're willing to go. It's a matter of deciding, for your use case, how complex you need to be and what kind of limits you're willing to place on the users.
If you are sure you want to use strings, you will have to write your own method to format those type names. Something like:
static string FormatType(Type t)
{
string result = t.Name;
if (t.IsGenericType)
{
result = string.Format("{0}<{1}>",
result.Split('`')[0],
string.Join(",", t.GetGenericArguments().Select(FormatType)));
}
return result;
}
This code assumes you have all necessary usings in your file.
But I think it's much better to actually use CodeDOM's object model. This way, you don't have to worry about usings, formatting types or typos:
var statement =
new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), property.Name),
new CodeDefaultValueExpression(new CodeTypeReference(property.PropertyType)));
And if you really don't want to use default(T), you can find out whether the type is a reference or value type. If it's a reference type, use null. If it's value type, the default constructor has to exist, and so you can call that.
I'm appalled I haven't found anything on the internet about this problem, but probably I'm looking for the wrong words. Here is what I need to do.
Suppose I have a generic type: List<string> works for the sake of simplicity. How do I get the parameter type (in this case typeof(string))?
Keep in mind that I need to do this from outside the generic class (not inside a class method, which is what I've seen in other SO questions). The bottom line is that I have an instance of a generic type, I need to know both its type AND its parameter type (in the example above, I would like to get both typeof(List) AND typeof(string), not anything like typeof(List<string>)). Of course, this must be done at runtime.
Thanks to everyone who will reply.
It sounds like what you're looking for is Type.GetGenericArguments(). You would call it on the Type of the instance in question. It returns an array of Type (to Eric Lippert's chagrin).
typeof(List<string>).GetGenericArguments()[0]
var myList = new List<String>();
var shouldBeString = myList.GetType().GetGenericArguments().FirstOrNull();
var shouldBeGenericList = myList.GetType().GetGenericTypeDefinition();
See http://msdn.microsoft.com/en-us/library/system.type.getgenericarguments.aspx and http://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition.aspx respectively
Why won't you make your function generic? It will let compiler sort it out for you.
void your_func<T>(List<T> lst)
{
Type list_type = typeof(List<T>);
Type generic_list_type = typeof(List<>);
Type generic_argument_type = typeof(T);
// do what you need
}
You can invoke it like normally:
var lst = new List<string>();
// ...
obj.your_func(lst);
Other option is to use reflection as described in other answers.
I am trying to use reflection to get all the (settable) properties in my POCO (which take a string argument, for now, but I plan to expand to other types), and set them to something arbitrary. (I need to make sure the .Equals method is implemented properly.)
I have some code in my unit tests that looks something like this (where t is the object under test, and u is a default version of that object):
foreach(var property in t.GetType().GetProperties())
{
var setMethod = property.GetSetMethod();
var type = setMethod.GetParameters()[0].GetType();
if(typeof(string).IsAssignableFrom(type))
{
setMethod.Invoke(t, new object[] {"a"});
Assert.IsFalse(t.Equals(u));
Assert.IsFalse(t.GetHashCode() == u.GetHashCode());
}
}
The place where this fails is where I say typeof(string).IsAssignableFrom(type). The code inside the if { ... } block never runs. How would I properly code up this part of the test?
You have confused ParameterInfo.GetType() with ParameterInfo.ParameterType. You should have:
var type = setMethod.GetParameters()[0].ParameterType;
.GetType() returns the Type of the current object, in this case ParameterInfo, which is obviously not what you want.
Let me start by saying I'm pretty new to using interfaces.
I'm writing a method (GetClaimDetails) that will return information about a medical insurance claim. If it is claim type A, it will return an list of the ClaimDetailA class. If claim type B, return list of ClaimDetailB class. Both of these classes share common properties but each have unique properties. The common properties are implemented in an interface.
I extracted an interface named IClaimDetail and set both to implement it. When i set the method to return IClaimDetail and have it return an instance of an object that implements IClaimsDetail, I get the compiler message
'Cannot implicitly convert type 'System.Collections.Generic.List DentalClaimDetail' to 'System.Collections.Generic.List IClaimDetail'
private static List<IClaimDetail> GetClaimDetailsB(string claimNumber, string connectionStringName)
{
var claimReportRows = new List<DentalClaimDetail>();
..removed for brevity
return claimReportRows;
}
public class DentalClaimDetail : IClaimDetail
{
...
}
When a method returns an interface, you just return an object the implements the interface. Correct? What am I doing wrong?
var claimReportRows = new List<IClaimDetail>();
Just change this. Then you will be able to insert DentalClaimDetail into it still.
Generics actually generate an type on-the-fly at compile time for every generic argument, so List<IClaimDetail> is one type, and List<DentalClaimDetail> is actually another type, so you will get compiler errors for that.
Yes, lame, but simply changing your call as outlined by Daniel A. White
var claimReportRows = new List<IClaimDetail>();
(although you should just be able to use the type directly unless you are using Linq) and then having the code use casting to cast the DentalClaimDetail to an IClaimDetail should do the trick.
If not using Linq, you can do something like:
List<IClaimDetail> claimReportRows = new List<IClaimDetail>();
//...populate Dentail Claims Here...
foreach(DentalClaimDetail dcd in dentalClaims)
{
claimReportRows.Add((IClaimDetail)dcd);
}
return claimReportRows.
Hope this helps!