I have a function that is declared like so:
public static string MultiWhereToString(List<WhereCondition<T>> whereConditions)
I am trying to pass it a variable called whereAnd which is delcared like so:
private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();
WhereAndCondition is a sub class of WhereCondition. It is declared like so:
public class WhereAndCondition<T> : WhereCondition<T>, IConditional where T : DatabaseObject
My issue is, if I try to execute the following code:
private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();
MultiWhereToString(whereAnd);
I get the following error:
Error 3 Argument 1: cannot convert from 'System.Collections.Generic.List<BrainStorm.WhereAndCondition<T>>' to 'System.Collections.Generic.List<BrainStorm.WhereCondition<T>>'
Any ideas on why? I think it has to do with the generics of the WhereCondition classes.
I would suggest using interfaces:
public static string MultiWhereToString(IEnumerable<ICondition<T>> whereConditions)
This would allow you a lot more freedom when calling this method.
Given:
class A {}
class A : B {}
An object of List<B> is not an instance of List<A>. So you can't cast a List<WhereAndCondition> to a List<WhereCondition>. You could use:
MultiWhereToString(whereAnd.OfType<WhereCondition>().ToList());
(There might also be a solution involving the in and out variance annotations, but I'm not terribly familiar with them.)
Your function is defined as taking a WhereCondition List, but you're passing it a WhereAndCondition List:
MultiWhereToString(List<WhereCondition<T>> whereConditions)
private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();
MultiWhereToString(whereAnd);
List variance has limited supported in .NET 4. See this question.
You can replace the entire WhereCondition<T> in your MultiWhereToString method with another generic type which is restricted to WhereCondition<T>.
Replace:
public static string MultiWhereToString(List<WhereCondition<T>> whereConditions)
With:
public static string MultiWhereToString<TType>(List<TType> whereConditions) where TType: WhereCondition<T>
Or alternatively change:
private List<WhereAndCondition<T>> whereAnd = new List<WhereAndCondition<T>>();
to:
private List<WhereCondition<T>> whereAnd = new List<WhereCondition<T>>();
And let inheritance take care of the rest for you.
This appears to be a covariance / contravariance issue.
Simplified to this:
public class WhereCondition
{
}
public class WhereAndCondition : WhereCondition
{
}
public class blah
{
public static void Blah()
{
List<WhereAndCondition> whereAnd = new List<WhereAndCondition>();
MultiWhereToString(whereAnd);
}
public static string MultiWhereToString(List<WhereCondition> whereConditions)
{
return null;
}
}
It's not going to work, because the list of WhereAndConditions can't be cast to List of WhereConditions:
Imagine it this way. You've got a list of giraffes, and the method is asking for a list of animals.
Without knowing what they are going to do with the list animals (like try adding a horse) the types are incompatible, but if you change it to something like this:
public static string MultiWhereToString(IEnumerable<WhereCondition> whereConditions)
{
return null;
}
Then the variance can kick in, and give you what you're looking for.
Generics have to be known explicitly at compile time because they are generated.
Why not use:
private List<WhereCondition<T>> whereAnd = new List<WhereCondition<T>>();
So you can still add WhereAndCondition objects to whereAnd.
Related
So I got an assignment [college student] to create a program that runs a garage. I have a class for every car type [FuelMotorcycle, ElectricMotorcycle, FuelCar, ElectricCar, etc.], each car type has its own constructor and they all differ from one another.
One of the assignment requirements is to "place the code that creates car objects [new], and this code alone, in a class on the logical part of the program, this code part cannot turn to the user directly or indirectly" (translated).
So the way I see it, I have a class, let's say "EmptyCarCreator" , that will have methods such as:
public static FuelMotorcycle CreateNewFuelMotorcycle()
{
FuelMotorcycle EmptyFuelMotorcycle;
return EmptyFuelMotorcycle;
}
obviously this won't compile, and even if it did, I couldn't use the "FuelMotorcycle" class constructor after I get it returned.
I need the user to input the elements for the constructor.
So, is there any other way to do this? I feel like I am missing something very basic here.
Please excuse any English errors, hope my question was clear.
You would need something like this:
public static class EmptyCarCreator
{
public static T Create<T>() where T : class, new()
{
return new T();
}
}
Then you would use it like this:
FuelMotorcycle myVehicle = EmptyCarCreator.Create<FuelMotorcycle>();
This will create a new class through the parameterless constructor.
There are other options that might be able to handle parameters a little better like this:
public static class EmptyCarCreator
{
public static object Create(Type type)
{
return Activator.CreateInstance(type);
}
}
To use this you would have to cast this returned object.
FuelMotorcycle myVehicle = (FuelMotorcycle)EmptyCarCreator.Create(typeof(FuelMotorcycle));
Is there some way to specify the type of the enclosing class declaration statically? If i had an instance, I could clearly use typeof(this), but statically I don't see a way.
Something like (where this_type is a placeholder):
public class Message
{
public static readonly int SizeInBytes = Marshal.SizeOf(typeof(this_type));
}
Clearly, I could just use the actual type name, but I've got several classes that follow this pattern and would like something less copy/paste error prone.
You can use MethodBase.GetCurrentMethod().DeclaringType but typeof(Message) is probably the cleaner way
public class Message
{
public static readonly int SizeInBytes = Marshal.SizeOf(MethodBase.GetCurrentMethod().DeclaringType);
}
Btw, you'll get a runtime exception when you execute this code as it is trying to get the size of a managed object.
typeof(Message) would be the closest you'd get here, but I think you'd need to use a struct rather than a class to do this from what I recall.
Perhaps:
public class Message
{
public static readonly int SizeInBytes = Marshal.SizeOf(typeof(Message));
}
This way, 'Message' can also be static.
What about an extension method on the type and get it dynamically instead of pushing it to a readonly static variable?
public static class Extensions
{
public static int SizeOfType(this System.Type tp) {
return Marshal.SizeOf(tp);
}
public static int SizeOfObjectType(this object obj) {
return obj.GetType().SizeOfType();
}
}
// calling it from a method, 2 ways
var size1 = this.GetType().SizeOfType();
var size2 = this.SizeOfObjectType();
var size3 = typeof(string).SizeOfType();
var size4 = "what is my type size".SizeOfObjectType();
After a short google search, I've seen other people using reflection to accomplish what you are talking about, but that comes with the caveat that it is probably a lot more expensive than just typing out typeof(this_type). I'd sooner recommend just typing it out.
Type t = MethodBase.GetCurrentMethod().DeclaringType
.NET: Determine the type of “this” class in its static method
I've been searching for awhile to see if anyone was trying to do something close to this and I find a bunch of people trying to interact with a generically typed List. I instead need to interact with a List of complex objects who are generically typed. Here's the current code.
public class RequestBundleItem<T> where T : BaseJsonResponseMessage
{
public T Response { get; private set; }
//intializers - code not needed
public void SetResponse(String jsonResponse)
{
Response = (T)jsonResponse.JsonToObject<T>();
}
}
public class RequestBundleManager
{
private List<RequestBundleItem<T>> BundleItems;
public async Task<List<RequestBundleItem<T>>> ProcessItemsAsync()
{
List<Task<JsonValueEventArgs>> tasks = //create tasks from bundleitems;
for (var i = 0; i < tasks.Count(); i++)
{
Task<JsonValueEventArgs> curTask = tasks[i];
var args = await curTask;
BundleItems[i].SetResponse(args.ValueAsText);
}
return BundleItems;
}
public void AddItem<T>(RequestBundleItem<T> newItem) where T : BaseJsonResponseMessage
{
BundleItems.Add(newItem);
}
}
This line is what's causing the problem
private List<RequestBundleItem<T>> BundleItems;
I don't know how to define this list since T is generic and just needs to implement BaseJsonResponseMessage but I don't want to type the RequestBundleManager itself.
SOLUTION:
I ended up removing the generic from the RequestBundleItem and the consumer is responsible for knowing the response type it needs back.
Make RequestBundleManager generic also:
public class RequestBundleManager<T>
And now you list can be defined with type T. Of course, you have to make sure that the T you use when creating your RequestBundleManger is the same as the one you used for RequestBundleItem, and you list will be homogeneous.
If you want your RequestBundleManager to handle lists with mixed T, then you will need to have RequestBundleItem derive from a base class or else have it implement an interface.
Define the list in your RequestBundleManager like this:
private List<RequestBundleItem<BaseJsonResponseMessage>>
If you don't put a type on the RequestBundleManager, you don't know the specific type of the object inside the list except that it's a BaseJsonResponseMessage. Then it makes sense to just define it like that. It will give you access only to methods defined in BaseJsonResponseMessage though.
If that's not enough, consider defining an interface with all the methods you want to have access to in the RequestBundleManager and put it as a constraint on your type in RequestBundleItem. Something like this:
public class RequestBundleItem<T> where T : BaseJsonResponseMessage, IMyInterface
Then define the list in RequestBundleManager like:
private List<RequestBundleItem<IMyInterface>>
I've got a class A with a public field b
class A
{
public static string b;
}
but now I want to make b dynamic so I call it anything. So I can make the class a DynamicObject
class A : DynamicObject
{
}
but I the compiler doesn't let me now call A.dynamicThing cos I have to instantiate A as dynamic.
How can I mangle c# further to make this work?
I don't belive you're going to find a way to make this work. It's not just the DynamicObject that makes things work. The declaration as a variable of the "dynamic" data type is what tells the compiler to actually use the DynamicObject base to resolve the member access. With static access direct to the class, you don't have that. So I really just don't think this is going to work in C# unless that changes in the future.
It's not possible right now with .NET 4
more information in this article.
I think I understand now - the closest you can get is by using an ExpandoObject :
dynamic foo = new ExpandoObject();
foo.somethinghere = "bar";
foo.dynamicThing = "baz";
Edit:
I don't think its possible to re-route the access to a static property of a class
to an expando object if the name of the property does not match - how would the compiler know that that's what you meant to do? You are getting a compile time error after all, not a runtime error.
From MSDN:
When a field, method, property, event,
operator, or constructor declaration
includes a static modifier, it
declares a static member. In addition,
a constant or type declaration
implicitly declares a static member.
Static members have the following
characteristics:
When a static member M is referenced in a member-access (Section 7.5.4)
of the form E.M, E must denote a type containing M.
...
public class FakeDynamicMethodInvoker : DynamicObject
{
// your code here
}
public class FakeDynamicWrapper<T>
{
static FakeDynamicWrapper()
{
DynamicStaticField = (dynamic)new FakeDynamicMethodInvoker();
}
public static T DynamicStaticField{ get; set; }
}
public class RealClassWithDynamicStaticField: FakeDynamicWrapper<dynamic>
{
}
somewhere in a code:
RealClassWithDynamicStaticField.DynamicStaticField.AnyMethod();
C# doesn't let you really rename variables to some dynamic name at runtime. Your question is mangled.
If you are wanting variable b to have a dynamic object at runtime, then use the dynamic keyword.
Example:
dynamic b = GetBValue();
b.SomeOperation(); // the type of "b" will be evaluated/chosen at runtime.
Old question but worth to answer :)
Static constructors are the answer to these problems.
https://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx
public class MyClass
{
public static dynamic StaticDynamicObject;
static MyClass()
{
StaticDynamicObject = new ExpandoObject();
StaticDynamicObject.Prop = "woohoo!";
}
}
I've seen a very interesting post on Fabio Maulo's blog. Here's the code and the bug if you don't want to jump to the url. I defined a new generic class like so:
public class TableStorageInitializer<TTableEntity> where TTableEntity : class, new()
{
public void Initialize()
{
InitializeInstance(new TTableEntity());
}
public void InitializeInstance(dynamic entity)
{
entity.PartitionKey = Guid.NewGuid().ToString();
entity.RowKey = Guid.NewGuid().ToString();
}
}
Note that InitializeInstance accepts one parameter, which is of type dynamic. Now to test this class, I defined another class that is nested inside my main Program class like so:
class Program
{
static void Main(string[] args)
{
TableStorageInitializer<MyClass> x = new TableStorageInitializer<MyClass>();
x.Initialize();
}
private class MyClass
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTime Timestamp { get; set; }
}
}
Note: the inner class "MyClass" is declared private.
Now if i run this code I get a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException on the line "entity.PartitionKey = Guide.NewGuid().ToString()".
The interesting part, though is that the message of the exception says "Object doesn't contain a definition for PartitionKey".
alt text http://img697.imageshack.us/img697/4188/testdl.png
Also note that if you changed the modifier of the nested class to public, the code will execute with no problems. So what do you guys think is really happening under the hood? Please refer to any documentation -of course if this is documented anywhere- that you may find?
The binder tries to work out an accessible class to treat the object as - in this case, the code making that call doesn't "know" about the MyClass class, so it doesn't "know" about PartitionKey either.
I don't know how thoroughly this is documented in the C# 4 spec - I know I've had an email conversation about it with Chris Burrows though, so the details may be somewhere on his blog :) Bear in mind that the dynamic binding has changed over time, so more recent posts are likely to be more accurate with respect to the RTM code.
I think that if you put PartitionKey into a public interface that the private class implements, that may work - but you'd have to try it.
There are various "gotchas" around dynamic typing. Explicit interface implementation has a similar problem:
public int Count(IList list)
{
int count1 = list.Count; // Fine
dynamic d = list;
int count2 = d.Count; // Should work, right?
}
This will fail if you pass in an array - because although IList.Count exists, it's implemented explicitly in arrays - so it's a bit like this:
string[] array = new string[10];
Console.WriteLine(array.Count); // Won't compile
The binder tries to treat the object as its concrete type, not as IList, hence the failure...