How to always have specific property?


B

Brett Romero

I'd like to design a class that is runtime typed (generic) and the
types will always have a specific member. For example:

public T MyClass
{
T temp = default(T);

Void Fill
{
T.PopulateMe();
}
}

What ever type I send in always has a method named PopulateMe(). I
imagine the types going into the class will need to implement an
interface with the one member. How do I then tell the generic class
(MyClass) that the member is always available since the parameter is
only T?

Thanks,
Brett
 
Ad

Advertisements

B

Barry Kelly

Brett Romero said:
I'd like to design a class that is runtime typed (generic) and the
types will always have a specific member. For example:

public T MyClass
{
T temp = default(T);

Void Fill
{
T.PopulateMe();
}
}

What ever type I send in always has a method named PopulateMe(). I
imagine the types going into the class will need to implement an
interface with the one member. How do I then tell the generic class
(MyClass) that the member is always available since the parameter is
only T?

---8<---
public interface IMyInterface
{
void PopulateMe();
}

public class MyClass<T>
where T : IMyInterface
{
T temp = default(T);

void Fill()
{
temp.PopulateMe();
}
}
--->8---

-- Barry
 
B

Brett Romero

Thanks Berry.

Let's say I want to use MyClass<> to create Person, Employee, and
Animal types.
Basically, MyClass <>is a container of several different objects.
However, each different instance is unaware that it is sharing
MyClass<> with other types.

I'd like to use the singleton pattern in MyClass<> so each of the three
types are created only once. If a type already exist, I get a
reference back. This is easy enough if there are concrete classes for
each of the three types. However, because I'm doing this via
MyClass<>, it needs to know if I have already created an instance of
MyClass<Person> for example and not create another instance. Instead
of coding a container class for each of the types, I'm using MyClass<>
as a template.

What is the approach here? I could first check if MyClass<> has been
instantiated at all. Each time some one instantiates it with a
different type, I store the type in a private List<>. I check the
List<> to see if the type exist (Person for example). If so, I return
a reference. If Person type has not been instantiated (not in the
List<>), I return a new instance. Any suggestions on a roadmap?


Thanks,
Brett
 
F

Fabio

Let's say I want to use MyClass<> to create Person, Employee, and
Animal types.
Basically, MyClass <>is a container of several different objects.
However, each different instance is unaware that it is sharing
MyClass<> with other types.

I think generics are not designed for this.
The right approach should be the simple inheritance:

class Animal
{}

class Dog : Animal
{}

class Person : Animal
{}

class Employee : Person
{}

class MyClass
{
public Animal SomeProperty
{}

public void SomeMethod(Animal animal)
{}

public Person GetPerson()
{}

public Employee GetEmployee()
{}

public Dog GetDog()
{}
}


Generics are designed to manage different types in the same way without
knowing about them, into a class of homogenous type.
You need to manage different types into the same class, and you know (you
need to know it if you store different types into the same class) what types
them are.
 
J

Jon Skeet [C# MVP]

Brett Romero said:
Let's say I want to use MyClass<> to create Person, Employee, and
Animal types.
Basically, MyClass <>is a container of several different objects.
However, each different instance is unaware that it is sharing
MyClass<> with other types.

I'd like to use the singleton pattern in MyClass<> so each of the three
types are created only once. If a type already exist, I get a
reference back. This is easy enough if there are concrete classes for
each of the three types. However, because I'm doing this via
MyClass<>, it needs to know if I have already created an instance of
MyClass<Person> for example and not create another instance. Instead
of coding a container class for each of the types, I'm using MyClass<>
as a template.

What is the approach here? I could first check if MyClass<> has been
instantiated at all. Each time some one instantiates it with a
different type, I store the type in a private List<>. I check the
List<> to see if the type exist (Person for example). If so, I return
a reference. If Person type has not been instantiated (not in the
List<>), I return a new instance. Any suggestions on a roadmap?

You can use the singleton pattern with generics with no problem. For
instance:

using System;
using System.Text;

class Singleton<T> where T : class, new()
{
static T instance;
static object padlock = new object();

public static T Instance
{
get
{
lock (padlock)
{
if (instance==null)
{
Console.WriteLine
("Creating instance of {0}", typeof(T));
instance=new T();
}
return instance;
}
}
}

}

class Test
{
static void Main()
{
StringBuilder x = Singleton<StringBuilder>.Instance;
object o = Singleton<object>.Instance;

Console.WriteLine (o == Singleton<object>.Instance);
}
}

Now, you can use the normal patterns of singletons in here - static
constructors/initializers etc. The only reason I've got constrains of
new() and class for T are to make it easier to demonstrate. You couild
easily use your interface as a constraint instead.
 
B

Brett Romero

You can use the singleton pattern with generics with no problem. For
instance:

using System;
using System.Text;

class Singleton<T> where T : class, new()
{
static T instance;
static object padlock = new object();

public static T Instance
{
get
{
lock (padlock)
{
if (instance==null)
{
Console.WriteLine
("Creating instance of {0}", typeof(T));
instance=new T();
}
return instance;
}
}
}

}


I'm doing something along those lines. My goal is to create a template
collection that can hold any type that implements a certain interface.
The way it works now, each time I give the collection a different
type, that creates a new singleton for that type. If I keep calling
properties on the collection for that type, I always reference the
singleton. It's working just the way I want it to.

public class MetaCollection<TValue> : where TValue : IMyCollection,
new()
{
private static MyCollection<TValue> _instance;

public static MyCollection<TValue> Instance
{
get
{
if( _instance == null )
_instance = new MyCollection<TValue>( );
}
}
}

But I keep getting a new instance back when I do:

MyCollection<someclass> SomeClassColl =
MyCollection<someclass>.Instance;

rather than getting the singleton. If I access a property on the
collection:

MyCollection<someclass>.Instance.Fill();
MyCollection<someclass>.Instance.GiveMeFirstItem();

for example, the singleton works fine. For now, I just use the entire
syntax. All I'm trying to do is provide a shortcut to the Instance
syntax. Do you know how I can get the shortcut to work using syntax
similar to the above?

I have actually wrapped the Instance check code inside of the above
methods, which is shorter syntax since I don't have to do ".Instance".
Still, I want to understand why the first line mentioned doesn't give
back a singleton.

Thanks,
Brett
 
Ad

Advertisements

J

Jon Skeet [C# MVP]

But I keep getting a new instance back when I do:

MyCollection<someclass> SomeClassColl =
MyCollection<someclass>.Instance;

rather than getting the singleton. If I access a property on the
collection:

MyCollection<someclass>.Instance.Fill();
MyCollection<someclass>.Instance.GiveMeFirstItem();

for example, the singleton works fine. For now, I just use the entire
syntax. All I'm trying to do is provide a shortcut to the Instance
syntax. Do you know how I can get the shortcut to work using syntax
similar to the above?

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
B

Brett Romero

Here it is:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;

namespace TestConsole
{
class TestCollection
{
public static void Main(string[]args)
{
Container < Person > p = Container < Person > .Instance;
}
}

public class Container < TValue > : Dictionary < int, TValue > where
TValue:
new()
{
private static Container < TValue > _instance;
private static Dictionary < string, TValue > _indexString = new
Dictionary
< string, TValue > ();

Container(){}

public static Container < TValue > Instance
{
get
{
if (_instance == null)
{
_instance = new Container < TValue > ();
}
return _instance;
}
}

public static bool IndexString(string pIndex, out TValue value)
{
if (_instance == null)
{
_instance = new Container < TValue > ();
}
return _indexString.TryGetValue(pIndex, out value);
}
}

public class Person
{
public Person(){}

public String Hand = "My Hand";
}
}


You'll noticed I can't do

p.IndexString(...)

p is an instance. All I want is a short to the longer syntax.
Everything is working fine except for the one thing. At this point,
I'd like to understand why it keeps giving back an instance rather than
a static reference. But when I do

Container < Person >.IndexString(...)

that is fine. It works on the singleton. What's the difference?

Note: I'm aware the dictionary is empty. This is just demonstrating
static access to a property.

Thanks,
Brett
 
J

Jon Skeet [C# MVP]

p is an instance. All I want is a short to the longer syntax.
Everything is working fine except for the one thing. At this point,
I'd like to understand why it keeps giving back an instance rather than
a static reference.

It's not at all clear what you mean - which is why I asked for a short
but complete program which demonstrates the problem. You've given a
program with a Main method, which is good, but the Main method doesn't
actually *do* anything. Note that if you change Main to:

Container < Person > p = Container < Person > .Instance;
Container < Person > p2 = Container < Person > .Instance;
Console.WriteLine (p==p2);

it prints "True" as expected.

What does it do which you don't expect?
 
B

Brett Romero

Container < Person > p = Container < Person > .Instance;

I can go along referencing the singleton this way:

Container < Person > .Instance

which is fine. For simplicity and to avoid so much typing, I'd like to
reference it this way:

Container said:
From now on, I reference "p" to access anything on the singleton:

p.IndexString(...)

p is now my shortcut syntax. But notice IndexString(...) is not
available on p. It's only available on the full syntax, which is:

Container < Person > .IndexString(...)

p is an instance and doesn't have the static property IndexString(...)
available to it. I'm only compressing the full syntax into a variable
that I'd like to be the singelton. Instead, it keeps coming back with
the instance.

Which part are you not sure on?

Thanks,
Brett
 
Ad

Advertisements

J

Jon Skeet [C# MVP]

Brett Romero said:
I can go along referencing the singleton this way:

Container < Person > .Instance

which is fine. For simplicity and to avoid so much typing, I'd like to
reference it this way:

Container < Person > p = Container < Person > .Instance

And that's fine.
p.IndexString(...)

p is now my shortcut syntax. But notice IndexString(...) is not
available on p. It's only available on the full syntax, which is:

Container < Person > .IndexString(...)

That's because it's a static method. Static methods are never available
through instances, because it can easily cause confusion. (Consider
calling Thread.Sleep "on" another thread - it looks like you're telling
the other thread to sleep, when in fact Thread.Sleep only ever makes
the current thread sleep.)

You need to decide whether you want it to be a static method which
automatically uses the singleton, or an instance method which should be
called *on* the singleton.
 
Ad

Advertisements


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top