|
the goal: use interfaces to enable creating a collection of different types of objects: and, then, at run-time cast back to the generic type without hard-coding specific types.
a. without using 'dynamic
b. without using reflection
c. without cloning/copying (using something like 'Activator.CreateInstance)
note: you might think you could:
a. use 'Convert.ChangeType : no, it is designed for conversion to a variety of primitive types, requires implementing IConvertible, and it returns an object.
b. use a 'ComponentModel.TypeConverter implementation per class: returns an object; internal method overrides cannot have return type modified
background:
A common pattern in creating heterogenous collections of different Type objects is making the various objects inherit from a generic Interface that itself inherits from a non-generic interface: by casting the instances of the generic interface to the non-generic interface, you then can create a collection you can compile.
when, at run-time, you have an instance of the non-generic interface, you can, then, "upcast" to the generic interface to expose fields, properties, methods unique to the generic type ... but ...
to upcast you need to:
1. know the Type
2. or, use a switch statement in which you use explicitly coded possible type matches
if you have a variable of type 'Type, there is no way to use its run-time value to upcast the non-generic interface instance !
public interface IBeing
{
string BName { get; set; }
Type BType { get; set; }
}
public interface IBeing<T> : IBeing where T : class
{
T Value { get; set; }
}
public class Being<T> : IBeing where T : class
{
public Being(string name, T value)
{
Value = value;
BName = name;
}
public T Value { get; set; }
public string BName { get; set; }
public Type BType { get; set; }
}
public class Human : IBeing
{
public Human(string name)
{
BName = name;
}
public Type BType { get; set; }
public string BName { get; set; }
}
public class Dog : IBeing
{
public Dog(string name)
{
BName = name;
}
public Type BType { get; set; }
public string BName { get; set; }
}
public class BeingCache
{
public BeingCache()
{
Beings = new List<IBeing>();
}
public List<IBeing> Beings { get; }
public IBeing AddBeing<T>(string name, T value) where T : class
{
Being<T> newbeing = new Being<T>(name, value);
newbeing.BType = typeof(T);
Beings.Add(newbeing);
return newbeing;
}
}
BeingCache beingCache = new BeingCache();
Human h1 = new Human("h1");
Dog d1 = new Dog("d1");
IBeing being1 = beingCache.AddBeing<Human>("Jack", h1);
IBeing being2 = beingCache.AddBeing<Dog>("Rover", d1);
IBeing being1human = beingCache.Beings[0];
IBeing being2dog = beingCache.Beings[1]; At this point, to convert the interface instance back to its generic form: IBeing<Human> backtogeneric1 = (IBeing<Human>) being1Human; will work.
And, a typical pattern is to have a 'switch statement that hard codes the conversion for each interface instancee Type.
But, consider: hard-coded conversion requires design-time "world knowledge" of each Type.
What is desired is a run-time conversion method that uses the Type stored in the interface instance to get the generic interface instance with it "payload" of other data.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
modified 24-Apr-20 10:50am.
|
|
|
|
|
If I understand the goal correctly (which maybe I don't), then it is inherently impossible, because even if you arranged to get an element casted to the right type, there is no way to represent the result. Any single type (this excludes dynamic because it is not a "single type") that you choose for a method that performs that conversion would be the wrong type - the only things that works are "useless types" (non-generic IBeing and object ). If you already knew the resulting type then you could do it, but then we're back to requiring that knowledge to be built in statically which you didn't want.
|
|
|
|
|
Hi Harold,
I embed an instance of the generic Type in the newly created interface instance. At run-time, I can pull that reference out: given I know the current interface instance type, and the destination generic type ... you'd think you could "rehydrate" (convert) without reflection, use of reflection, 'dynamic, etc.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
The problem is that you don't know at compile-time what the run-time type of the instance will be.
As Harold said, there isn't a compile-time type you can use which would give you access to the properties or methods of the run-time type.
Consider:
public abstract class Being
{
public string Name { get; set; }
}
public class Dog : Being
{
public void Bark() { ... }
}
public class Human : Being
{
public void ComposeMusic() { ... }
}
List<Being> beings = LoadBeings();
Being aBeing = beings[0];
Type beingType = aBeing.GetType();
{ What could possibly go here? } myBeing = BeingAsType(aBeing, beingType);
myBeing.{ Which method could you call here? }();
Perhaps the visitor pattern might help you?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks, Richard, if you look at the code I posted, you will see that as the generic instance is created, the generic Type is injected into the instance.
public IBeing AddBeing<T>(string name, T value) where T : class
{
Being<T> newbeing = new Being<T>(name, value);
newbeing.BType = typeof(T);
Beings.Add(newbeing);
return newbeing;
} when the generic Type is added to the interface instance collection, it is "downcast" to the interface, but the Type variable is there, and accessible from the interface instance at run time.
Your code example has no relevance to the issue here.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
I disagree.
You have a variable with the compile-time type of IBeing , and the run-time type of IBeing<T> for some T . You can find the T at run-time, either by accessing a property on the instance, or by examining the run-time type of the instance.
What compile-time type could you possibly use for the variable to make it match the unknown run-time type? And what properties or methods could you possibly access on that variable that aren't declared on the base type?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
BillWoodruff wrote: But, consider: hard-coded conversion requires design-time "world knowledge" of each Type.
What is desired is a run-time conversion method t
I doubt that is what you want.
When you use the case statement, as you stated, the reason you do that is not because you want the specific type but rather because you want to do/access something that is specific to that type.
So given that you had the type then how are you going to do something specific with it if you don't code it in the first place?
I will note that I do know of one way to get what I suspect what you want but it still depends on what how would then subsequently use that type (the question above.)
|
|
|
|
|
|
Either:
1) You assumed - wrongly - this is FarceBok.
2) You are a spam tester.
I'm guessing the later...
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I've worked a lot to try to get this working, but after several errors and trials, i've tried two things without error, but it doesn't work
here is my customer list load code
SQLiteParameter[] param = {};
customerList.Rows.Clear();
DataTable searchinfo = database.query_search("SELECT id, firstname, lastname FROM customers", param);
foreach (DataRow row in searchinfo.Rows)
{
customerList.Rows.Add(row[0].ToString(), row[1].ToString() + " " + row[2].ToString());
}
statusLabel.Text = searchinfo.Rows.Count.ToString() + " row(s) returned";
double clicking or clicking an 'edit' button successfully raises a child form
private void customerList_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
int index = e.RowIndex;
DataGridViewRow row = customerList.Rows[index];
String cid = row.Cells[0].Value.ToString();
editcustomer editdiag = new editcustomer();
editdiag.id = cid;
editdiag.ShowDialog();
}
I used a timer to filter results from a textbox that starts and stops based on textchanged
private void search_TextChanged(object sender, EventArgs e)
{
if(queryInterval.Enabled == false)
queryInterval.Start();
}
here is the 1000ms tick that stops itself after an idle match
public void queryInterval_Tick(object sender, EventArgs e)
{
if (lastQuery == search.Text)
{
queryInterval.Stop();
}
else
{
if (search.Text.Trim() != "" && search.Text.Length >= 3)
{
customerList.Rows.Clear();
SQLiteParameter[] param = {
new SQLiteParameter("@search", "%" + search.Text + "%")
};
DataTable searchinfo = database.query_search("SELECT id, firstname, lastname FROM customers WHERE firstname LIKE @search OR lastname LIKE @search", param);
foreach (DataRow row in searchinfo.Rows)
{
customerList.Rows.Add(row[0].ToString(), row[1].ToString() + " " + row[2].ToString());
}
statusLabel.Text = searchinfo.Rows.Count.ToString() + " row(s) returned";
}
else if (search.Text.Trim() == "")
{
SQLiteParameter[] param = { };
customerList.Rows.Clear();
DataTable searchinfo = database.query_search("SELECT id, firstname, lastname FROM customers", param);
foreach (DataRow row in searchinfo.Rows)
{
customerList.Rows.Add(row[0].ToString(), row[1].ToString() + " " + row[2].ToString());
}
statusLabel.Text = searchinfo.Rows.Count.ToString() + " row(s) returned";
}
else if (search.Text.Length < 3 && search.Text.Trim() != "")
{
}
lastQuery = search.Text;
}
}
i've tried directly running the load from the parent form on the child close
private void editcustomer_FormClosed(object sender, FormClosedEventArgs e)
{
customers custForm = new customers();
custForm.refresh(sender, e);
custForm.customers_Load(sender, e);
}
or blanked out the match text and started the timer
private void editcustomer_FormClosed(object sender, FormClosedEventArgs e)
{
customers custForm = new customers();
custForm.lastQuery = "";
custForm.queryInterval.Start();
}
I've done messageboxes in both the interval and the load and it does execute it, but the datagridview refuses to update. Is the parent form marked disabled till the form totally closes? Is there a better way to do this i'm not seeing?
yeah point is close the edit form and update the database and close the child form, have the parent update (name information updated, irrelevant if other data not seen is updated)
would iterating through the parent datagridview with the ID and upadting it manually work? I somehow doubt it if the other two is running, but not clearing the data and updating the new rows with the database data
thanks, sorry about the complexity of this
|
|
|
|
|
Your problem is to do with the way you display the child form: ShowDialog is a modal function: it does not return until the form it displays is closed. So the UI for Form1 is "busy" and doesn't get updated while the child form still exists.
Instead of ShowDialog, you can use Show - which allows both forms to continue working - but in any case you are going at this the wrong way:
1) Creating a new instance of the "parent" form and calling it's methods will not affect the existing one: it's a separate instance and does not share a DataGridView with any other. In order to directly update the parent, you would need to use the actual instance that opened the child, not a new one.
2) But the child form shouldn't even know the parent form exists, much less what type it is, or what methods it contains. Instead, the child should raise events that the parent handles and let teh parent do what it wants with the updates.
That probably sounds complicated, but it actually solves both your problems very neatly. Have a look here:
Transferring information between two forms, Part 2: Child to Parent[^]
It will show you how to do it properly.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
lol I actually ran across that page during my research. It sounds real complicated. a little blood just dropped from my nose
|
|
|
|
|
It's not difficult at all, not really - you've got the full code, and all it's doing is using the same event mechanism that everything else does, just you are creating and raising the event as well as handling it.
And creating an event is almost trivial, I do it so often I created a Visual Studio shortcut to to make it even simpler: A Simple Code Snippet to Add an Event[^]. Now I just type "evh" and press TAB and it fills out the event, just like "prop"+TAB creates a property.
Raising the event is just a case of calling a method!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I tried, and got errors, even downloaded the zip and it's pretty confusing. Keep in mind i've been doing c# for like, two weeks? Gotten fairly far using just google searches. Some specific things do elude me. Like your code. Still have a lot of specific stuff to figure out. like things like seeing {get; set;} at top and things like that I just don't understand. Mind you this program is going to be used by just me, nor will I be doing any business-level programming. I did some of that with PHP but never continued and never learned ajax/dhtml, which a lot of web sites require. My specialty is repair/support (which this program is for me to keep track of that)
aaaanyways, I found a solution, that I think I did put in my original post, but just using .show allowed my original form call to create a FormClosedEventHandler from the parent, which works. So now the child is doing nothing aware from the parent...sort of
|
|
|
|
|
Then you are trying to get way ahead of yourself - if you don't understand the basics like automatic properties:
MyType MyProperty { get; set; } Then you are missing huge chunks, and you need to wonder what else you have missed, and how it might have improved things and made your life - and code - easier.
How are you learning? A course, a book, YouTube (gawd forbid!), guesswork?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
modified 23-Apr-20 6:16am.
|
|
|
|
|
google searches, guesswork. But as you can tell from my code i'm not doing TOO bad. I know some of the .net concepts, and did pretty well with vb.net (but I hate the syntax of vb.net)
did borland C++ in high school and a little in college to get me past the required single beginning programming class (my comp sci was focused for computer repair)
|
|
|
|
|
I guessed it might be that - it shows in your code.
Do yourself a favour - a pretty big favour - and get a book (Addison Wesley, Wrox, MS Press all do good ones, and there is also the Yellow Book[^] which is pretty good, and free).
A book has structure, and leads you through the topics - and at the very least makes you aware of stuff you might use even if you don't study it well. Random guesses and searching doesn't do that: if you don't know it exists or what it's called you can't find it out!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
wow $40. I'm not going to be making any money off my code so and it's a program just for me (and an easy one at that), i'll probably skip this, at least for the time being
|
|
|
|
|
Technical books aren't cheap because they take a lot of time and effort to write - and the author has to put a lot of work into learning how to teach and his subject before he even starts. (That's why most "how to code" videos on YouTube are such crap: the author doesn't know his subject well, he does kn ow how to teach, and he has no idea how to make a video.)
But the Yellow Book is free (there is a download on the page I linked to) and some of the others can be borrowed from public libraries or bought second hand. For those a lot less ethical, many of them can be stolen from the internet as EPUB or PDF files as well.
If we go back to cars, you are trying to learn to drive a F1 race by stealing Ford Fiestas and stamping on the throttle. If you don't know how the clutch works or even that "it's the pedal on the left" your gear changes are going to be noisy and clumsy forever; if you don't know which side the petrol filler cap is you're going to have fun at the fuel station; if you don't know that tires need a specific air pressure you're going to wear them out very quickly. And even if you guess all that eventually you still aren't going to beat Louis Hamilton!
With C# and the .NET framework, there is so much "stuff" that can make your life easier - if you use it right - that you won't even begin to guess it's in there! Linq, generics, interfaces, using blocks, try...finally, the Diagnostics class, overloading, databses, transactions, delegates, ... the list goes on a very, very long way.
The only way to find them is to learn them - and that means a book, or better a course, honestly.
Get the Yellow Book, and read it. It's a pretty good starting point.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
yeah I know about try...finally some generics and heh yeah overloading is beyond me. I've read about it and seen code samples, and delegates I have a blurry idea at best, because I have seen other code samples but yeah the base concept will have to be learned in a basic to advanced way a book does
again this program is easy, well...yeah I did have that big problem, but I overcame it. It's simple database and form stuff. I know a good amount about databases already with my time using php/mysql, but yeah I know there is a unifying sql subsystem in c# I haven't played with that has to do with sources, and binding, etc
|
|
|
|
|
The easiest way to do what you want is to create a static Globals class, and create the object in question in that class. At that point, it exists everywhere in the app, and you can read/modify the class' properties from any form.
It may not be "the best way", but it's probably the easiest way.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Please help me
I need to calculate the balance columns in datagridview
For Example
DR CR Balance
100 0 100
200 0 200
0 100 100
|
|
|
|
|
Try adding the numbers together.
|
|
|
|
|
And what would you like us to do?
Social Media - A platform that makes it easier for the crazies to find each other.
Everyone is born right handed. Only the strongest overcome it.
Fight for left-handed rights and hand equality.
|
|
|
|
|
Responding to a QA question today, I was, finally, able to figure out the proper calling syntax for an extension method on Enum with a signature like this:
public static TEnum ToEnum<TEnum>(this Type tenum, string str, bool ignorecase = false)
where TEnum : struct, IConvertible{ ... } An example of the calling syntax:
WeekDays friday = typeof(WeekDays).ToEnum<WeekDays>("friday"); It kind of drove me crazy to figure this out, and the usual resources here, and on SO, didn't turn up any clues.
Assuming a week of days with temperature above 105F, plus adjusting to a locked-down city with high air-pollution, and a curfew, has not addled my brain more than old age ...
I wonder if it's possible I stumbled on something ... new. I seriously doubt that: more likely I came across something so weird nobody would want to do that.
Curious if you have seen this technique/syntax. I find it damn awkward.
Of course, I do expect @RichardDeeming to weigh-in and expose my ...
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|